Support wildcard redirect_uri patterns for OAuth clients

theta42/proxy fronts an arbitrary number of hosts behind SSO, each with its
own callback URL (https://<host>/__proxy_auth/callback) — proxy's own code
comment already assumed "a wildcard redirect URI covers all", but no
wildcard matching existed here, so every proxied host's callback had to be
registered on the shared OAuth client individually or /oauth/authorize
would reject it with InvalidRedirectURI.

Add `*` (one hostname label) / `**` (any number of labels) wildcard support
to redirect_uri matching, e.g. `https://**.example.com/__proxy_auth/callback`
now covers every host proxy fronts under example.com. Exact matches still
work exactly as before.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-15 00:42:32 -04:00
parent a52f5ce53d
commit 4c6b1e38b1
5 changed files with 83 additions and 2 deletions
+66
View File
@@ -0,0 +1,66 @@
'use strict';
const { redirectUriAllowed } = require('../routes/oauth');
// Pure logic, no LDAP/Redis needed -- regression coverage for the bug where
// theta42/proxy's per-host SSO callback (a different URL per proxied host,
// e.g. https://site.example.com/__proxy_auth/callback) could never match a
// single OAuth client's redirect_uris list without registering every host's
// callback individually. `*`/`**` wildcard support lets one registered
// pattern (e.g. https://*.example.com/__proxy_auth/callback) cover a whole
// domain's worth of proxied hosts.
describe('redirectUriAllowed', () => {
test('exact match still works with no wildcard present', () => {
expect(redirectUriAllowed(
['https://app.example.com/cb'],
'https://app.example.com/cb'
)).toBe(true);
});
test('rejects a uri that is not registered', () => {
expect(redirectUriAllowed(
['https://app.example.com/cb'],
'https://app.example.com/cb2'
)).toBe(false);
});
test('* matches exactly one hostname label', () => {
expect(redirectUriAllowed(
['https://*.example.com/__proxy_auth/callback'],
'https://site.example.com/__proxy_auth/callback'
)).toBe(true);
});
test('* does not span multiple labels', () => {
expect(redirectUriAllowed(
['https://*.example.com/__proxy_auth/callback'],
'https://site.nl.example.com/__proxy_auth/callback'
)).toBe(false);
});
test('** spans multiple labels', () => {
expect(redirectUriAllowed(
['https://**.example.com/__proxy_auth/callback'],
'https://site.nl.example.com/__proxy_auth/callback'
)).toBe(true);
});
test('scheme mismatch is not allowed even with a wildcard', () => {
expect(redirectUriAllowed(
['https://*.example.com/__proxy_auth/callback'],
'http://site.example.com/__proxy_auth/callback'
)).toBe(false);
});
test('a wildcard pattern does not match an unrelated domain', () => {
expect(redirectUriAllowed(
['https://**.example.com/__proxy_auth/callback'],
'https://evil.com/__proxy_auth/callback'
)).toBe(false);
});
test('empty/missing patterns list rejects everything', () => {
expect(redirectUriAllowed([], 'https://app.example.com/cb')).toBe(false);
expect(redirectUriAllowed(undefined, 'https://app.example.com/cb')).toBe(false);
});
});