📝 Reformat code for improved readability and consistency in the OAuth composable
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
/**
|
||||
* Unified OAuth Composable
|
||||
*
|
||||
*
|
||||
* Handles OAuth flow for multiple providers (Challonge, Discord, etc.)
|
||||
*
|
||||
*
|
||||
* Features:
|
||||
* - Multi-provider token storage with localStorage persistence
|
||||
* - Authorization URL generation with return_to support
|
||||
@@ -11,7 +11,7 @@
|
||||
* - Automatic token refresh with 5-minute expiry buffer
|
||||
* - Token validation and cleanup
|
||||
* - Comprehensive error handling
|
||||
*
|
||||
*
|
||||
* Usage:
|
||||
* const oauth = useOAuth('challonge');
|
||||
* oauth.login({ scope: 'tournaments:read tournaments:write', return_to: '/challonge-test' });
|
||||
@@ -111,20 +111,24 @@ export function useOAuth(provider = 'challonge') {
|
||||
|
||||
/**
|
||||
* Generate authorization URL for OAuth flow
|
||||
*
|
||||
*
|
||||
* @param {string|Object} scopeOrOptions - Scope string or options object
|
||||
* @param {Object} options - Additional options (scope, return_to)
|
||||
* @returns {Object} {authUrl, state, returnTo}
|
||||
* @throws {Error} If OAuth credentials not configured
|
||||
*/
|
||||
function getAuthorizationUrl(scopeOrOptions, options = {}) {
|
||||
const clientId = import.meta.env[`VITE_${provider.toUpperCase()}_CLIENT_ID`];
|
||||
const redirectUri = import.meta.env[`VITE_${provider.toUpperCase()}_REDIRECT_URI`];
|
||||
const clientId = import.meta.env[
|
||||
`VITE_${provider.toUpperCase()}_CLIENT_ID`
|
||||
];
|
||||
const redirectUri = import.meta.env[
|
||||
`VITE_${provider.toUpperCase()}_REDIRECT_URI`
|
||||
];
|
||||
|
||||
if (!clientId || !redirectUri) {
|
||||
throw new Error(
|
||||
`OAuth credentials not configured for ${provider}. ` +
|
||||
`Check VITE_${provider.toUpperCase()}_CLIENT_ID and VITE_${provider.toUpperCase()}_REDIRECT_URI in .env`
|
||||
`Check VITE_${provider.toUpperCase()}_CLIENT_ID and VITE_${provider.toUpperCase()}_REDIRECT_URI in .env`
|
||||
);
|
||||
}
|
||||
|
||||
@@ -167,7 +171,7 @@ export function useOAuth(provider = 'challonge') {
|
||||
/**
|
||||
* Start OAuth authorization flow
|
||||
* Redirects user to OAuth provider
|
||||
*
|
||||
*
|
||||
* @param {Object} options - Options including scope and return_to
|
||||
* @throws {Error} If OAuth credentials missing
|
||||
*/
|
||||
@@ -182,7 +186,10 @@ export function useOAuth(provider = 'challonge') {
|
||||
sessionStorage.setItem('oauth_return_to', returnTo);
|
||||
}
|
||||
|
||||
console.log(`🔐 Starting ${provider} OAuth flow with state:`, state.substring(0, 8) + '...');
|
||||
console.log(
|
||||
`🔐 Starting ${provider} OAuth flow with state:`,
|
||||
state.substring(0, 8) + '...'
|
||||
);
|
||||
|
||||
// Redirect to OAuth provider
|
||||
window.location.href = authUrl;
|
||||
@@ -196,7 +203,7 @@ export function useOAuth(provider = 'challonge') {
|
||||
/**
|
||||
* Exchange authorization code for access token
|
||||
* Called from OAuth callback page
|
||||
*
|
||||
*
|
||||
* @param {string} code - Authorization code from OAuth provider
|
||||
* @param {string} stateParam - State parameter for CSRF validation
|
||||
* @returns {Promise<Object>} Tokens object {access_token, refresh_token, expires_at, ...}
|
||||
@@ -214,7 +221,9 @@ export function useOAuth(provider = 'challonge') {
|
||||
}
|
||||
|
||||
if (storedProvider !== provider) {
|
||||
const err = new Error(`Provider mismatch: expected ${storedProvider}, got ${provider}`);
|
||||
const err = new Error(
|
||||
`Provider mismatch: expected ${storedProvider}, got ${provider}`
|
||||
);
|
||||
state.error.value = err.message;
|
||||
throw err;
|
||||
}
|
||||
@@ -268,7 +277,9 @@ export function useOAuth(provider = 'challonge') {
|
||||
sessionStorage.removeItem('oauth_provider');
|
||||
sessionStorage.removeItem('oauth_return_to');
|
||||
|
||||
console.log(`✅ ${provider} OAuth authentication successful, expires in ${data.expires_in}s`);
|
||||
console.log(
|
||||
`✅ ${provider} OAuth authentication successful, expires in ${data.expires_in}s`
|
||||
);
|
||||
return tokens;
|
||||
} catch (err) {
|
||||
state.error.value = err.message;
|
||||
@@ -282,7 +293,7 @@ export function useOAuth(provider = 'challonge') {
|
||||
/**
|
||||
* Refresh access token using refresh token
|
||||
* Called when token is expired or about to expire
|
||||
*
|
||||
*
|
||||
* @returns {Promise<Object>} Updated tokens object
|
||||
* @throws {Error} If no refresh token available or refresh fails
|
||||
*/
|
||||
@@ -331,7 +342,9 @@ export function useOAuth(provider = 'challonge') {
|
||||
state.tokens.value = tokens;
|
||||
localStorage.setItem(state.storageKey, JSON.stringify(tokens));
|
||||
|
||||
console.log(`✅ ${provider} token refreshed, new expiry in ${data.expires_in}s`);
|
||||
console.log(
|
||||
`✅ ${provider} token refreshed, new expiry in ${data.expires_in}s`
|
||||
);
|
||||
return tokens;
|
||||
} catch (err) {
|
||||
state.error.value = err.message;
|
||||
@@ -348,7 +361,7 @@ export function useOAuth(provider = 'challonge') {
|
||||
/**
|
||||
* Get valid access token, refreshing if necessary
|
||||
* Automatically refreshes tokens expiring within 5 minutes
|
||||
*
|
||||
*
|
||||
* @returns {Promise<string>} Valid access token
|
||||
* @throws {Error} If not authenticated
|
||||
*/
|
||||
@@ -363,7 +376,9 @@ export function useOAuth(provider = 'challonge') {
|
||||
|
||||
// Refresh if expired or expiring within 5 minutes
|
||||
if (expiresIn < fiveMinutes) {
|
||||
console.log(`🔄 ${provider} token expiring in ${Math.floor(expiresIn / 1000)}s, refreshing...`);
|
||||
console.log(
|
||||
`🔄 ${provider} token expiring in ${Math.floor(expiresIn / 1000)}s, refreshing...`
|
||||
);
|
||||
await refreshTokenFn();
|
||||
}
|
||||
|
||||
@@ -386,13 +401,15 @@ export function useOAuth(provider = 'challonge') {
|
||||
/**
|
||||
* Generate random state for CSRF protection
|
||||
* Uses crypto.getRandomValues for secure randomness
|
||||
*
|
||||
*
|
||||
* @returns {string} 64-character hex string
|
||||
*/
|
||||
function generateState() {
|
||||
const array = new Uint8Array(32);
|
||||
crypto.getRandomValues(array);
|
||||
return Array.from(array, byte => byte.toString(16).padStart(2, '0')).join('');
|
||||
return Array.from(array, byte => byte.toString(16).padStart(2, '0')).join(
|
||||
''
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user