[PR #8686] feat(oauth-provider): add validateRedirectUri option for custom redirect validation #16393

Open
opened 2026-04-13 10:30:39 -05:00 by GiteaMirror · 0 comments
Owner

Original Pull Request: https://github.com/better-auth/better-auth/pull/8686

State: open
Merged: No


Summary

Add a validateRedirectUri option to the OAuth provider that allows custom redirect URI validation logic. This enables use cases like wildcard pattern matching for preview deployments without requiring database modification or workarounds.

Motivation

Platforms like Vercel, Netlify, and Cloudflare Pages generate unique subdomains for each PR/branch preview deployment (e.g., pr-123.preview.example.com, deploy-preview-456.netlify.app). Currently, Better Auth only supports exact string matching for redirect URIs, which means:

  1. Each preview URL must be registered individually (impractical)
  2. Users resort to workarounds like database hooks to temporarily inject URIs (security concerns)

This PR provides a clean, secure API to implement custom validation logic.

Use Cases

  • Preview deployments: Match *.preview.example.com for CI/CD preview URLs
  • Multi-tenant applications: Match *.tenants.example.com for tenant subdomains
  • Development environments: Match localhost with any port

Changes

packages/oauth-provider/src/types/index.ts

  • Added validateRedirectUri option to OAuthOptions interface
  • Comprehensive JSDoc documentation with use cases and security considerations

packages/oauth-provider/src/authorize.ts

  • Modified redirect URI validation to use custom validator when provided
  • Added try-catch to handle validator exceptions (fail-closed for security)
  • Falls back to exact string matching when no validator is provided (backward compatible)

packages/oauth-provider/src/authorize.test.ts

  • Added test suite for custom validateRedirectUri functionality
  • Tests cover: acceptance of matching URIs, rejection of non-matching URIs, exception handling

docs/content/docs/plugins/oauth-provider.mdx

  • Added "Custom Redirect URI Validation" section
  • Includes code examples and security warnings

API

oauthProvider({
  validateRedirectUri: (redirectUri, registeredUris) => {
    // Return true if valid, false otherwise
    // Example: implement wildcard matching
    return registeredUris.some((pattern) => {
      if (!pattern.includes('*')) return pattern === redirectUri;
      const regex = new RegExp('^' + pattern.replace(/\*/g, '[^.]+') + '$');
      return regex.test(redirectUri);
    });
  },
})

Security Considerations

The implementation follows security best practices:

  1. Fail-closed: If no validator is provided, exact string matching is used
  2. Exception handling: If the custom validator throws, the request is rejected (fail-closed)
  3. No information leakage: Invalid redirect URIs are redirected to an error page, not to the attacker-controlled URI
  4. Documentation warnings: Clear warnings about public suffixes, HTTPS requirements, and overly broad patterns

Test Plan

  • Existing tests pass
  • New tests for custom validator functionality
  • Test for validator exception handling (fail-closed)
  • Lint and format pass
  • Build succeeds

Breaking Changes

None. This is a purely additive change with full backward compatibility.

**Original Pull Request:** https://github.com/better-auth/better-auth/pull/8686 **State:** open **Merged:** No --- ## Summary Add a `validateRedirectUri` option to the OAuth provider that allows custom redirect URI validation logic. This enables use cases like wildcard pattern matching for preview deployments without requiring database modification or workarounds. ## Motivation Platforms like **Vercel**, **Netlify**, and **Cloudflare Pages** generate unique subdomains for each PR/branch preview deployment (e.g., `pr-123.preview.example.com`, `deploy-preview-456.netlify.app`). Currently, Better Auth only supports exact string matching for redirect URIs, which means: 1. Each preview URL must be registered individually (impractical) 2. Users resort to workarounds like database hooks to temporarily inject URIs (security concerns) This PR provides a clean, secure API to implement custom validation logic. ## Use Cases - **Preview deployments**: Match `*.preview.example.com` for CI/CD preview URLs - **Multi-tenant applications**: Match `*.tenants.example.com` for tenant subdomains - **Development environments**: Match `localhost` with any port ## Changes ### `packages/oauth-provider/src/types/index.ts` - Added `validateRedirectUri` option to `OAuthOptions` interface - Comprehensive JSDoc documentation with use cases and security considerations ### `packages/oauth-provider/src/authorize.ts` - Modified redirect URI validation to use custom validator when provided - Added try-catch to handle validator exceptions (fail-closed for security) - Falls back to exact string matching when no validator is provided (backward compatible) ### `packages/oauth-provider/src/authorize.test.ts` - Added test suite for custom `validateRedirectUri` functionality - Tests cover: acceptance of matching URIs, rejection of non-matching URIs, exception handling ### `docs/content/docs/plugins/oauth-provider.mdx` - Added "Custom Redirect URI Validation" section - Includes code examples and security warnings ## API ```typescript oauthProvider({ validateRedirectUri: (redirectUri, registeredUris) => { // Return true if valid, false otherwise // Example: implement wildcard matching return registeredUris.some((pattern) => { if (!pattern.includes('*')) return pattern === redirectUri; const regex = new RegExp('^' + pattern.replace(/\*/g, '[^.]+') + '$'); return regex.test(redirectUri); }); }, }) ``` ## Security Considerations The implementation follows security best practices: 1. **Fail-closed**: If no validator is provided, exact string matching is used 2. **Exception handling**: If the custom validator throws, the request is rejected (fail-closed) 3. **No information leakage**: Invalid redirect URIs are redirected to an error page, not to the attacker-controlled URI 4. **Documentation warnings**: Clear warnings about public suffixes, HTTPS requirements, and overly broad patterns ## Test Plan - [x] Existing tests pass - [x] New tests for custom validator functionality - [x] Test for validator exception handling (fail-closed) - [x] Lint and format pass - [x] Build succeeds ## Breaking Changes None. This is a purely additive change with full backward compatibility.
GiteaMirror added the pull-request label 2026-04-13 10:30:39 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#16393