diff --git a/gateway/src/routes/oidc/authorize.ts b/gateway/src/routes/oidc/authorize.ts index 7aacb10..ca9ccb2 100644 --- a/gateway/src/routes/oidc/authorize.ts +++ b/gateway/src/routes/oidc/authorize.ts @@ -82,7 +82,10 @@ export function createAuthorizeRouter( } // Validate redirect_uri + console.log(`[OIDC] Validating redirect_uri: "${redirect_uri}"`); + console.log(`[OIDC] Allowed redirect_uris: ${JSON.stringify(client.redirect_uris)}`); if (!client.redirect_uris.includes(redirect_uri)) { + console.log(`[OIDC] redirect_uri mismatch!`); return res.status(400).json({ error: 'invalid_request', error_description: 'Invalid redirect_uri', @@ -128,49 +131,187 @@ export function createAuthorizeRouter( expires_at: Math.floor(Date.now() / 1000) + 600, // 10 minutes }; - // Store state for callback - // We use the AT Protocol OAuth flow as the identity provider - // Generate AT Protocol OAuth URL - const atprotoAuth = await oauthService.generateAuthUrl( + // Store the OIDC authorization request and show login page + // We need the user's handle before we can start AT Protocol OAuth + + // Save the pending authorization request + db.saveAuthorizationCode({ + code: authCode, client_id, - '', // No handle yet - will be filled by user - `${oidcService.issuer}/oauth/callback` - ); + redirect_uri, + scope: scopeValidation.scopes.join(' '), + nonce, + code_challenge, + code_challenge_method: code_challenge_method as 'S256' | 'plain' | undefined, + did: '', // Will be filled on callback + handle: '', // Will be filled on callback + created_at: authState.created_at, + expires_at: authState.expires_at, + used: false, + }); - if (!atprotoAuth) { - return redirectWithError(res, redirect_uri, state, 'server_error', 'Failed to generate auth URL'); - } + // Show login page asking for handle + const loginPageHtml = ` + + +
+ + +Use your Bluesky or AT Protocol identity
- // Store our OIDC state in the database, keyed by AT Protocol state - const atprotoState = atprotoAuth.state; - if (atprotoState) { - db.saveAuthorizationCode({ - code: authCode, - client_id, - redirect_uri, - scope: scopeValidation.scopes.join(' '), - nonce, - code_challenge, - code_challenge_method: code_challenge_method as 'S256' | 'plain' | undefined, - did: '', // Will be filled on callback - handle: '', // Will be filled on callback - created_at: authState.created_at, - expires_at: authState.expires_at, - used: false, - }); +