🔒 Add Discord admin user permissions and update developer access check logic
This commit is contained in:
137
code/websites/pokedex.online/DISCORD_PERMISSIONS_SETUP.md
Normal file
137
code/websites/pokedex.online/DISCORD_PERMISSIONS_SETUP.md
Normal file
@@ -0,0 +1,137 @@
|
||||
# Discord User Permissions Setup Guide
|
||||
|
||||
## Overview
|
||||
|
||||
The app now checks Discord usernames/IDs to grant developer tool access. Users must be in the allowlist to access developer features.
|
||||
|
||||
## Configuration
|
||||
|
||||
### 1. Find Your Discord Username/ID
|
||||
|
||||
You can use any of the following to identify users:
|
||||
|
||||
- **Username**: Your current Discord username (e.g., `fragginwagon`)
|
||||
- **Global Name**: Your display name (if different from username)
|
||||
- **Discord ID**: Your numeric Discord ID (e.g., `123456789012345678`)
|
||||
|
||||
**How to Find Your Discord ID:**
|
||||
1. Enable Developer Mode in Discord: Settings → Advanced → Developer Mode (ON)
|
||||
2. Right-click your username anywhere → Copy User ID
|
||||
3. Or use this Discord bot command: `/userinfo` or `!userinfo`
|
||||
|
||||
### 2. Configure Environment Variables
|
||||
|
||||
Add allowed users to your `.env` file:
|
||||
|
||||
```env
|
||||
# Discord User Permissions
|
||||
# Comma-separated list of Discord usernames, display names, or IDs
|
||||
DISCORD_ADMIN_USERS=fragginwagon,AnotherUser,123456789012345678
|
||||
```
|
||||
|
||||
**Multiple formats supported:**
|
||||
```env
|
||||
# Just usernames
|
||||
DISCORD_ADMIN_USERS=fragginwagon,coolguy99
|
||||
|
||||
# Mix of usernames and IDs
|
||||
DISCORD_ADMIN_USERS=fragginwagon,123456789012345678,coolguy99
|
||||
|
||||
# Using Discord IDs (most reliable)
|
||||
DISCORD_ADMIN_USERS=123456789012345678,987654321098765432
|
||||
```
|
||||
|
||||
### 3. Location of Configuration
|
||||
|
||||
**Development (.env file):**
|
||||
```bash
|
||||
/Users/fragginwagon/Developer/MemoryPalace/code/websites/pokedex.online/server/.env
|
||||
```
|
||||
|
||||
**Production (Docker):**
|
||||
Add to your `docker-compose.tmp.yml` or production environment:
|
||||
```yaml
|
||||
environment:
|
||||
- DISCORD_ADMIN_USERS=fragginwagon,user2,123456789012345678
|
||||
```
|
||||
|
||||
Or in your server's `.env` file that gets loaded by Docker.
|
||||
|
||||
## How It Works
|
||||
|
||||
1. User logs in with Discord OAuth
|
||||
2. Backend fetches user info from Discord API
|
||||
3. Backend checks if username, global name, OR Discord ID matches the allowlist
|
||||
4. Backend returns `permissions: ['developer_tools.view']` if user is authorized
|
||||
5. Frontend checks `hasDevAccess()` to show/hide developer tools
|
||||
|
||||
## Testing
|
||||
|
||||
### Test if you're in the allowlist:
|
||||
|
||||
1. Add your Discord username to `DISCORD_ADMIN_USERS` in `.env`
|
||||
2. Restart the backend server:
|
||||
```bash
|
||||
docker compose -f docker-compose.tmp.yml restart backend
|
||||
```
|
||||
3. Log in with Discord OAuth in the app
|
||||
4. Open Developer Tools (should now be visible if authorized)
|
||||
|
||||
### Check backend logs:
|
||||
|
||||
Look for these messages:
|
||||
```
|
||||
✅ Discord user authenticated { username: 'fragginwagon', id: '123456789012345678' }
|
||||
✅ Discord user granted developer access { username: 'fragginwagon' }
|
||||
```
|
||||
|
||||
Or if not authorized:
|
||||
```
|
||||
✅ Discord user authenticated { username: 'unauthorized', id: '999999999999999999' }
|
||||
```
|
||||
|
||||
## Security Notes
|
||||
|
||||
- **Case-insensitive matching**: Usernames are compared in lowercase
|
||||
- **Multiple formats**: Supports username, display name, and Discord ID
|
||||
- **Fallback behavior**: If Discord user info fetch fails, no permissions are granted (fail-safe)
|
||||
- **No permissions stored client-side**: Permissions are checked on every OAuth login
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**Developer tools not appearing after adding username:**
|
||||
1. Check backend logs for "Discord user authenticated" message
|
||||
2. Verify your username matches exactly (check for typos)
|
||||
3. Try using your Discord ID instead of username (more reliable)
|
||||
4. Ensure backend restarted after changing `.env`
|
||||
|
||||
**"Failed to fetch Discord user info" in logs:**
|
||||
- OAuth token may not have `identify` scope
|
||||
- Check Discord OAuth app settings
|
||||
- Verify `VITE_DISCORD_CLIENT_ID` and `DISCORD_CLIENT_SECRET` are correct
|
||||
|
||||
## Example Configuration
|
||||
|
||||
```env
|
||||
# Development
|
||||
NODE_ENV=development
|
||||
PORT=3099
|
||||
|
||||
# Discord OAuth
|
||||
VITE_DISCORD_CLIENT_ID=your_client_id_here
|
||||
DISCORD_CLIENT_SECRET=your_client_secret_here
|
||||
VITE_DISCORD_REDIRECT_URI=http://localhost:5173/oauth/callback
|
||||
|
||||
# Allowed Users (add your Discord username or ID)
|
||||
DISCORD_ADMIN_USERS=fragginwagon,123456789012345678
|
||||
```
|
||||
|
||||
## Permission Levels
|
||||
|
||||
Currently implemented:
|
||||
- `developer_tools.view` - Access to developer tools panel and feature flags
|
||||
|
||||
Future permissions (not yet implemented):
|
||||
- `admin` - Full admin access
|
||||
- `gamemaster.edit` - Edit gamemaster data
|
||||
- `tournaments.manage` - Manage tournaments
|
||||
@@ -180,6 +180,13 @@ export function getConfig() {
|
||||
// Security
|
||||
session: {
|
||||
secret: process.env.SESSION_SECRET || 'dev-secret-change-in-production'
|
||||
},
|
||||
|
||||
// Discord User Permissions
|
||||
discord: {
|
||||
adminUsers: process.env.DISCORD_ADMIN_USERS
|
||||
? process.env.DISCORD_ADMIN_USERS.split(',').map(u => u.trim().toLowerCase())
|
||||
: []
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -98,20 +98,14 @@ export function useDiscordOAuth() {
|
||||
|
||||
/**
|
||||
* Check if user is allowed to access developer tools
|
||||
* Compares Discord username against backend-managed allowlist
|
||||
* Checks permissions returned from backend during OAuth
|
||||
*
|
||||
* @param {Object} userPermissions - User permissions object from backend
|
||||
* @returns {boolean} True if user has developer access
|
||||
*/
|
||||
function hasDevAccess(userPermissions = {}) {
|
||||
// Check explicit permission
|
||||
if (userPermissions?.includes?.('developer_tools.view')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Backend could also return discord_username_allowlist
|
||||
// This would be checked server-side, but frontend can cache it
|
||||
return false;
|
||||
function hasDevAccess() {
|
||||
// Check if tokens include permissions
|
||||
const permissions = oauth.tokens.value?.permissions || [];
|
||||
return permissions.includes('developer_tools.view');
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user