✨ Add composable for handling Discord OAuth integration
This commit is contained in:
138
code/websites/pokedex.online/src/composables/useDiscordOAuth.js
Normal file
138
code/websites/pokedex.online/src/composables/useDiscordOAuth.js
Normal file
@@ -0,0 +1,138 @@
|
||||
/**
|
||||
* Discord OAuth Composable
|
||||
*
|
||||
* Thin wrapper around useOAuth for Discord-specific flows
|
||||
* Handles Discord user profile fetching and username access
|
||||
*
|
||||
* Usage:
|
||||
* const discord = useDiscordOAuth();
|
||||
* discord.login();
|
||||
* // ... OAuth flow ...
|
||||
* const username = discord.discordUsername;
|
||||
*/
|
||||
|
||||
import { ref, computed } from 'vue';
|
||||
import { useOAuth } from './useOAuth.js';
|
||||
|
||||
// Shared Discord user profile data
|
||||
const discordUser = ref(null);
|
||||
|
||||
export function useDiscordOAuth() {
|
||||
const oauth = useOAuth('discord');
|
||||
|
||||
const hasDiscordAuth = computed(() => oauth.isAuthenticated.value);
|
||||
|
||||
const discordUsername = computed(() => {
|
||||
return discordUser.value?.username || null;
|
||||
});
|
||||
|
||||
const discordId = computed(() => {
|
||||
return discordUser.value?.id || null;
|
||||
});
|
||||
|
||||
const discordTag = computed(() => {
|
||||
if (!discordUser.value) return null;
|
||||
// Format: username#discriminator or just username (newer Discord)
|
||||
return discordUser.value.discriminator
|
||||
? `${discordUser.value.username}#${discordUser.value.discriminator}`
|
||||
: discordUser.value.username;
|
||||
});
|
||||
|
||||
/**
|
||||
* Fetch Discord user profile from backend
|
||||
* Backend will use the stored Discord token to fetch from Discord API
|
||||
*
|
||||
* @returns {Promise<Object>} Discord user profile
|
||||
* @throws {Error} If fetch fails
|
||||
*/
|
||||
async function fetchUserProfile() {
|
||||
try {
|
||||
const token = oauth.accessToken.value;
|
||||
if (!token) {
|
||||
throw new Error('Not authenticated with Discord');
|
||||
}
|
||||
|
||||
// Fetch from backend which has the Discord token
|
||||
const response = await fetch('/api/auth/discord/profile', {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`
|
||||
}
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await response.json().catch(() => ({}));
|
||||
throw new Error(error.error || 'Failed to fetch Discord profile');
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
discordUser.value = data.user;
|
||||
|
||||
console.log(`✅ Loaded Discord profile: ${data.user.username}`);
|
||||
return data.user;
|
||||
} catch (err) {
|
||||
console.error('Failed to fetch Discord profile:', err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Login with Discord
|
||||
* Uses identify scope only for minimal permissions
|
||||
*
|
||||
* @param {Object} options - Optional options (return_to, etc.)
|
||||
*/
|
||||
function login(options = {}) {
|
||||
oauth.login({
|
||||
...options,
|
||||
scope: 'identify'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Logout from Discord
|
||||
*/
|
||||
function logout() {
|
||||
oauth.logout();
|
||||
discordUser.value = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if user is allowed to access developer tools
|
||||
* Compares Discord username against backend-managed allowlist
|
||||
*
|
||||
* @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;
|
||||
}
|
||||
|
||||
return {
|
||||
// State
|
||||
hasDiscordAuth,
|
||||
discordUser: computed(() => discordUser.value),
|
||||
discordUsername,
|
||||
discordId,
|
||||
discordTag,
|
||||
isExpired: oauth.isExpired,
|
||||
expiresIn: oauth.expiresIn,
|
||||
loading: oauth.loading,
|
||||
error: oauth.error,
|
||||
|
||||
// Methods
|
||||
login,
|
||||
logout,
|
||||
exchangeCode: oauth.exchangeCode,
|
||||
refreshToken: oauth.refreshToken,
|
||||
getValidToken: oauth.getValidToken,
|
||||
fetchUserProfile,
|
||||
hasDevAccess
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user