Skip to content

feat(oauth): RFC 8414 authorization server discovery metadata#1132

Open
jjackson wants to merge 1 commit intodimagi:mainfrom
jjackson:feat/oauth-discovery-metadata
Open

feat(oauth): RFC 8414 authorization server discovery metadata#1132
jjackson wants to merge 1 commit intodimagi:mainfrom
jjackson:feat/oauth-discovery-metadata

Conversation

@jjackson
Copy link
Copy Markdown
Member

Summary

Adds /.well-known/oauth-authorization-server serving OAuth 2.0 authorization
server metadata per RFC 8414. Enables modern OAuth clients — including a remote
MCP server being built in commcare-connect-labs — to auto-discover endpoints
instead of hardcoding them.

django-oauth-toolkit doesn't ship this endpoint by default, which is why this
needs to be added manually.

What's advertised

  • issuer: the server's canonical base URL
  • authorization_endpoint, token_endpoint, introspection_endpoint, userinfo_endpoint
  • grant types: authorization_code, refresh_token
  • code_challenge_methods: S256 only (no plain-PKCE)
  • scopes: sourced from existing oauth2_provider config — single source of truth

Test plan

🤖 Generated with Claude Code

Adds /.well-known/oauth-authorization-server serving OAuth 2.0 authorization
server metadata per RFC 8414. Modern OAuth clients (including MCP clients)
use this to auto-configure rather than hardcoding endpoint URLs.

Advertised endpoints: /o/authorize/, /o/token/, /o/introspect/, /o/userinfo/.
Code-challenge: S256 only. Scopes sourced from existing oauth2_provider config.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 20, 2026

Walkthrough

This pull request adds OAuth 2.0 Authorization Server metadata discovery functionality. A new view function oauth_authorization_server is added to handle GET requests at /.well-known/oauth-authorization-server, constructing and returning RFC 8414 compliant JSON metadata including issuer information, endpoint URLs, supported scopes, grant types, response types, and PKCE methods. The response includes a Cache-Control header set to 3600 seconds. A new URL route maps this endpoint to the view, and comprehensive test coverage verifies the response format, header values, endpoint URL correctness, and HTTP method constraints.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 9.09% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The pull request title clearly and concisely summarizes the main change: adding RFC 8414 OAuth authorization server discovery metadata endpoint.
Description check ✅ Passed The pull request description is directly related to the changeset, providing detailed context about the OAuth 2.0 discovery endpoint implementation and its purpose.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
config/tests/test_oauth_discovery.py (1)

12-14: Add at least one URLconf-level smoke test.

_get() calls the view directly, so these tests can pass even if the .well-known route or name="oauth_authorization_server" wiring regresses. Add one client.get(reverse("oauth_authorization_server"), secure=True) assertion to cover the actual public endpoint.

Example addition
+def test_discovery_route_is_wired(client):
+    response = client.get(reverse("oauth_authorization_server"), secure=True)
+    assert response.status_code == 200
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@config/tests/test_oauth_discovery.py` around lines 12 - 14, The tests call
the view directly via the helper _get (which uses oauth_authorization_server),
so add a URLconf-level smoke test that exercises the real endpoint: in
config/tests/test_oauth_discovery.py create a test that uses the Django test
client to perform client.get(reverse("oauth_authorization_server"), secure=True)
and assert a successful response (e.g., status_code 200 and expected JSON keys),
ensuring the .well-known route and the name "oauth_authorization_server" are
wired correctly; keep the existing _get helper tests but add this one
client-based assertion to cover routing.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@config/views.py`:
- Around line 11-20: The metadata construction uses the incoming request
(request.scheme/request.get_host and absolute()) which makes issuer and endpoint
URLs vary by Host; change it to use the project's canonical public base URL
(e.g. settings.CONNECTID_URL) instead: build the issuer from
settings.CONNECTID_URL and construct authorization/token/introspection/userinfo
endpoints by joining that canonical base with reverse("oauth2_provider:...")
paths (use urllib.parse.urljoin or equivalent) rather than
request.build_absolute_uri; update the absolute() helper to accept a base URL or
remove it and reference settings.CONNECTID_URL where metadata is created so
metadata["issuer"] and the endpoint entries are stable and derived from the
configured CONNECTID_URL, not the request.

---

Nitpick comments:
In `@config/tests/test_oauth_discovery.py`:
- Around line 12-14: The tests call the view directly via the helper _get (which
uses oauth_authorization_server), so add a URLconf-level smoke test that
exercises the real endpoint: in config/tests/test_oauth_discovery.py create a
test that uses the Django test client to perform
client.get(reverse("oauth_authorization_server"), secure=True) and assert a
successful response (e.g., status_code 200 and expected JSON keys), ensuring the
.well-known route and the name "oauth_authorization_server" are wired correctly;
keep the existing _get helper tests but add this one client-based assertion to
cover routing.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8a0d88ab-9d02-4a59-9baa-efdaa2ce181c

📥 Commits

Reviewing files that changed from the base of the PR and between 9eed70d and 7acc332.

📒 Files selected for processing (4)
  • config/tests/__init__.py
  • config/tests/test_oauth_discovery.py
  • config/urls.py
  • config/views.py

Comment thread config/views.py
@jjackson
Copy link
Copy Markdown
Member Author

I create this PR because I'm trying to develop a server side MCP for connect-labs to help people more easily edit workflows. Claude thinks this is ideal so I'm not creating a token caching layer to be able to call to use the user's oauth to read/write to the labsrecord apis

@mkangia mkangia requested a review from calellowitz April 21, 2026 07:30
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.

1 participant