Skip to content

feat: wildcard redirect-allowlist support; enable ChatGPT connector#46

Merged
imonroe merged 2 commits into
mainfrom
claude/zen-babbage-eOZ3p
May 23, 2026
Merged

feat: wildcard redirect-allowlist support; enable ChatGPT connector#46
imonroe merged 2 commits into
mainfrom
claude/zen-babbage-eOZ3p

Conversation

@imonroe
Copy link
Copy Markdown
Owner

@imonroe imonroe commented May 23, 2026

Summary

Enables ChatGPT (Developer Mode custom connectors) to connect via OAuth, and makes the redirect allowlist robust to per-connector callbacks.

Background

ChatGPT's OAuth callback isn't a fixed URL — the diagnostic logging from #43 revealed it sends a per-connector redirect URI:

https://chatgpt.com/connector/oauth/eaQ3VyiNzLuI

The <id> segment is unique to each connector, so an exact-match allowlist breaks whenever a connector is deleted/recreated.

Change

  • Wildcard prefix matching in OAUTH_ALLOWED_REDIRECT_URIS: an entry ending in * matches any redirect URI with that prefix. The wildcard only extends the path under a fixed scheme+host the operator configured, so it can't redirect authorization codes to a different host (verified by a host-locking test).
  • Default allowlist now includes https://chatgpt.com/connector/oauth/*, so ChatGPT works out of the box alongside the existing claude.ai/Cowork entries.
  • Exact-match behavior is unchanged.

Tests

  • test_dcr_allows_wildcard_prefix — a ChatGPT per-connector callback registers (201).
  • test_dcr_wildcard_is_host_lockedevil.com/... and chatgpt.com.evil.com/... are still rejected (400).
  • Existing exact-match and rejection tests unchanged.
  • 72 tests pass; ruff clean.

Docs

  • New "ChatGPT (OAuth, Developer Mode)" section in the User Guide.
  • Config table + .env.example document the trailing-* prefix syntax and the ChatGPT default.

https://claude.ai/code/session_01U3EtN3puoZRq2t7nedcnHY


Generated by Claude Code

ChatGPT's connector callback is per-connector
(https://chatgpt.com/connector/oauth/<id>), so an exact-match allowlist
breaks whenever a connector is recreated. Support a trailing "*" in
OAUTH_ALLOWED_REDIRECT_URIS entries as a scheme+host-locked prefix match,
and add https://chatgpt.com/connector/oauth/* to the default allowlist so
ChatGPT works out of the box.

Exact matches are unchanged. Add tests covering wildcard acceptance and
host-locking, and document ChatGPT setup + the wildcard syntax.

https://claude.ai/code/session_01U3EtN3puoZRq2t7nedcnHY
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the OAuth Dynamic Client Registration (DCR) redirect-URI allowlist to support wildcard prefix entries (to handle ChatGPT’s per-connector callback URLs), adds ChatGPT’s callback prefix to the default allowlist, and documents the new configuration and setup.

Changes:

  • Add wildcard * suffix support for OAUTH_ALLOWED_REDIRECT_URIS entries (prefix matching).
  • Extend the default redirect allowlist with https://chatgpt.com/connector/oauth/*.
  • Add tests for wildcard acceptance + host-locking, and document ChatGPT connector setup and wildcard syntax.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
app/oauth.py Implements wildcard-aware redirect URI allowlist checks during DCR registration.
app/config.py Adds ChatGPT wildcard callback prefix to the default redirect allowlist.
tests/test_oauth.py Adds tests verifying wildcard prefix acceptance and rejecting lookalike hosts.
docs/USER_GUIDE.md Documents ChatGPT OAuth connector setup and wildcard allowlist syntax.
.env.example Updates example configuration to include wildcard syntax and ChatGPT default entry.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread app/oauth.py
Comment on lines +131 to +142
def _redirect_uri_allowed(uri: str, allowed: list[str]) -> bool:
# Exact match, or prefix match for an allowlist entry ending in "*". The
# wildcard only extends the path under a fixed scheme+host the operator
# configured (e.g. ChatGPT's per-connector https://chatgpt.com/connector/oauth/*),
# so it can't redirect codes to a different host.
for entry in allowed:
if entry.endswith("*"):
if uri.startswith(entry[:-1]):
return True
elif uri == entry:
return True
return False
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch — fixed in a733085. _redirect_uri_allowed now parses both the pattern and candidate with urllib.parse.urlsplit, requires an exact scheme + netloc match, and prefix-matches only on path. Over-broad patterns lacking a concrete host or path (*, https://*, https://chatgpt.com*) are ignored rather than honored, so a misconfigured entry can no longer match chatgpt.com.evil.com. Added a unit test covering these cases.


Generated by Claude Code

Comment thread docs/USER_GUIDE.md Outdated
| `PUBLIC_BASE_URL` | yes | — | Public URL, e.g. `https://mem0.your-domain.com`. Used in OAuth metadata. |
| `OAUTH_SIGNING_KEY` | no | empty | PEM RSA private key. **Setting this enables Phase 2 OAuth.** Leave blank for Phase 1. |
| `OAUTH_ALLOWED_REDIRECT_URIS` | no | claude.ai + cowork callbacks | Comma-separated allowlist for OAuth redirect URIs. |
| `OAUTH_ALLOWED_REDIRECT_URIS` | no | claude.ai + cowork + chatgpt callbacks | Comma-separated allowlist for OAuth redirect URIs. An entry ending in `*` is a prefix match (e.g. `https://chatgpt.com/connector/oauth/*`, since ChatGPT uses a per-connector callback path). |
Comment thread docs/USER_GUIDE.md
Comment on lines +213 to +215
connector you create. The default allowlist already covers these via the prefix entry
`https://chatgpt.com/connector/oauth/*`, so you don't need to add the exact URL. If you've
customized `OAUTH_ALLOWED_REDIRECT_URIS`, include that wildcard entry.
Address review: the previous wildcard used a raw startswith, so the
"host-locked" claim wasn't actually enforced -- a misconfigured entry like
https://chatgpt.com* would match lookalike hosts (chatgpt.com.evil.com).

Parse both the pattern and candidate with urlsplit, require an exact
scheme+netloc match, and prefix-match only on path. Over-broad patterns
lacking a concrete host or path (*, https://*, https://chatgpt.com*) are
ignored rather than honored. Add a unit test for these cases and clarify
the docs on the required scheme://host/path/ wildcard format.

https://claude.ai/code/session_01U3EtN3puoZRq2t7nedcnHY
@imonroe imonroe merged commit c432b0d into main May 23, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants