Skip to content

feat(auth): OIDC Discovery and redirect_uri support for OAuth compliance #95

@getlarge

Description

@getlarge

Summary

While integrating with Ory Hydra for OAuth authentication, I discovered that the current OAuth client implementation has compatibility issues with providers that don't follow the /oauth/* endpoint convention.

The implementation hardcodes endpoint paths that don't work with OAuth providers using different conventions:

Function Hardcoded Path Ory Hydra Path
createAuthorizationRequest /oauth/authorize /oauth2/auth
exchangeCodeForToken /oauth/token /oauth2/token
refreshToken /oauth/token /oauth2/token
validateToken /oauth/introspect /oauth2/introspect
dynamicClientRegistration /oauth/register /oauth2/register

Additionally, the OAuth authorization flow is missing required OIDC parameters:

  • redirect_uri in authorization request (required by OIDC 1.0)
  • redirect_uri in token exchange (must match authorization request)
  • /oauth/callback not skipped in auth prehandler

Error from Ory when using the current implementation:

The 'redirect_uri' parameter is required when using OpenID Connect 1.0.

Proposed Solution

1. OIDC Discovery

Fetch endpoints from /.well-known/openid-configuration with caching (5 min TTL):

async function discoverOIDCEndpoints(authorizationServer: string, logger?: FastifyBaseLogger) {
  // Fetch from /.well-known/openid-configuration
  // Cache results for 5 minutes
  // Fallback to hardcoded /oauth/* paths for backwards compatibility
}

2. redirect_uri in Authorization Request

// In auth-routes.ts /oauth/authorize
const callbackUrl = `${opts.resourceUri || `${request.protocol}://${request.host}`}/oauth/callback`;
const authRequest = await fastify.oauthClient.createAuthorizationRequest({
  ...(resource && { resource }),
  redirect_uri: callbackUrl
});

3. redirect_uri in Token Exchange

Store callbackUrl in session, pass to exchangeCodeForToken:

async exchangeCodeForToken(code, pkce, state, receivedState, redirectUri) {
  // Include redirect_uri in token request body (must match authorization request)
}

4. Skip /oauth/callback in Auth Prehandler

if (request.url.startsWith('/oauth/authorize') || request.url.startsWith('/oauth/callback')) {
  return;
}

5. Optional: Excluded Paths Configuration

Allow health checks etc. to bypass auth:

type AuthorizationConfig = {
  enabled: true;
  // ...existing fields...
  excludedPaths?: (string | RegExp)[];
}

Files to Modify

  • src/auth/oauth-client.ts - OIDC discovery, redirect_uri in token exchange
  • src/auth/prehandler.ts - Skip callback, excludedPaths support
  • src/routes/auth-routes.ts - Include redirect_uri, store in session
  • src/types/auth-types.ts - Add excludedPaths to config type

Backwards Compatibility

  • OIDC discovery fails gracefully to default /oauth/* paths
  • All existing authorization configs continue working
  • excludedPaths is optional

I'm happy to submit a PR with these changes. I have a working implementation tested against Ory Hydra.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions