Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
26d4dad
feat(oauth): add MCP / RFC 8707 + RFC 8414 compatibility
appleboy May 14, 2026
a4926d3
fix(oauth): address Copilot review findings on MCP compatibility
appleboy May 14, 2026
b765220
fix(oauth): address second round of Copilot review findings
appleboy May 14, 2026
4e10389
fix(oauth): close open-redirect, fix refresh-aud, harden audience inv…
appleboy May 14, 2026
66e61d0
fix(oauth): bind device-code resource, fix introspection aud, close r…
appleboy May 15, 2026
eb92f3a
fix(oauth): make UserAuthorization resource-aware, close 7 more Copil…
appleboy May 15, 2026
b634503
fix(oauth): close 6 more Copilot threads — device confirm, cascade-re…
appleboy May 15, 2026
e41d8d2
fix(oauth): close 7 more Copilot threads — POST deny redirect, resour…
appleboy May 15, 2026
baf8cc4
fix(oauth): close 4 more Copilot threads — deny PKCE, refresh aud, at…
appleboy May 15, 2026
0a591dc
fix(oauth): close 5 more Copilot threads — txn expiry, introspect aud…
appleboy May 15, 2026
9ab39e9
fix(oauth): close 3 more Copilot threads — revert unsafe introspect a…
appleboy May 15, 2026
77cb30b
refactor(oauth): consolidate audience helpers and resource-narrowing …
appleboy May 16, 2026
8edb5f8
style(css): style RFC 8707 resource indicator UI elements
appleboy May 16, 2026
581c0e7
style(authorize): visually distinguish resource indicators from scopes
appleboy May 17, 2026
15e18d4
docs: document MCP / RFC 8707 / RFC 8414 support and aud verification
appleboy May 17, 2026
ce76227
docs(flows): document resource indicator usage on each grant guide
appleboy May 17, 2026
62ae7d5
docs: add architecture, use case, and troubleshooting coverage for re…
appleboy May 17, 2026
9793298
style(docs): normalize markdown emphasis to underscore form
appleboy May 17, 2026
4d080d2
style(readme): realign endpoints table columns
appleboy May 17, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 37 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# AuthGate

> A lightweight OAuth 2.0 Authorization Server supporting Device Authorization Grant ([RFC 8628][rfc8628]), Authorization Code Flow with PKCE ([RFC 6749][rfc6749] + [RFC 7636][rfc7636]), and Client Credentials Grant for machine-to-machine authentication
> A lightweight OAuth 2.0 Authorization Server supporting Device Authorization Grant ([RFC 8628][rfc8628]), Authorization Code Flow with PKCE ([RFC 6749][rfc6749] + [RFC 7636][rfc7636]), Client Credentials Grant for machine-to-machine authentication, and Resource Indicators ([RFC 8707][rfc8707]) for MCP / multi-audience deployments

[![Security Scanning](https://github.com/go-authgate/authgate/actions/workflows/security.yml/badge.svg)](https://github.com/go-authgate/authgate/actions/workflows/security.yml)
[![Lint and Testing](https://github.com/go-authgate/authgate/actions/workflows/testing.yml/badge.svg)](https://github.com/go-authgate/authgate/actions/workflows/testing.yml)
Expand Down Expand Up @@ -86,6 +86,8 @@ AuthGate also serves as a lightweight **centralised identity gateway** for inter
- 🏢 Enterprise teams needing **token self-service** — users manage and revoke their own active sessions and per-app grants via the built-in web UI (`/account/sessions`, `/account/authorizations`), no admin intervention required. Admins can additionally create accounts, disable or re-enable users (revoking all tokens immediately), and inspect or unlink each user's third-party OAuth connections and authorized apps from `/admin/users/:id`.
- 🔑 Organisations wanting a **unified internal SSO portal** — centralise login across all internal tools and services through a single OAuth 2.0 gateway, eliminating per-system password management
- 🔍 **Security & compliance teams** — comprehensive audit logs of every authentication, token, and admin event with filtering and CSV export (`/admin/audit`), satisfying audit and regulatory requirements
- 🧩 **[Model Context Protocol (MCP)][mcp-spec] servers** — drop-in OAuth 2.1 authorization server with [RFC 8707][rfc8707] Resource Indicators, [RFC 8414][rfc8414] AS metadata at `/.well-known/oauth-authorization-server`, and CORS on the well-known group for browser-based MCP clients (see [MCP Integration Guide](docs/MCP.md))
- 🎯 **Multi-resource-server APIs** — per-request audience binding ([RFC 8707][rfc8707]): a token requested for `https://api-a.corp` cannot be replayed at `https://api-b.corp` (the JWT `aud` is bound at issuance and verified by each resource server)

### The Enterprise Case for AuthGate

Expand Down Expand Up @@ -155,6 +157,8 @@ AuthGate also serves as a lightweight **centralised identity gateway** for inter
- **OIDC `email_verified`**: Persists and exposes `email_verified` claims from upstream OAuth providers in ID tokens and UserInfo responses
- **Dynamic Client Registration ([RFC 7591][rfc7591])**: Programmatic client registration with admin approval workflow, protected by optional initial access token
- **Token Introspection ([RFC 7662][rfc7662])**: RFC-compliant token metadata inspection with client credential authentication
- **Resource Indicators ([RFC 8707][rfc8707])**: Per-request `resource` parameter on all four grants binds the issued JWT's `aud` to the target resource server(s); refresh requests enforce RFC 8707 §2.2 subset-narrowing so a granted audience can never be widened
- **OAuth 2.0 AS Metadata ([RFC 8414][rfc8414])**: Curated OAuth-only discovery document at `/.well-known/oauth-authorization-server` alongside the existing OIDC discovery — required by [MCP][mcp-spec] clients and other RFC 8414-aware tooling. CORS is applied to the `/.well-known/*` group so browser-based clients can fetch it

---

Expand Down Expand Up @@ -267,7 +271,8 @@ The Authorization Code Flow CLI starts a local callback server, opens your brows
- **[Device Code Flow Guide](docs/DEVICE_CODE_FLOW.md)** - CLI and IoT authentication, polling, token lifecycle, Go implementation
- **[Authorization Code Flow Guide](docs/AUTHORIZATION_CODE_FLOW.md)** - Auth Code Flow, PKCE, user consent, admin controls
- **[Client Credentials Flow Guide](docs/CLIENT_CREDENTIALS_FLOW.md)** - Machine-to-machine authentication, M2M token management
- **[JWT Verification Guide](docs/JWT_VERIFICATION.md)** - Verify tokens at resource servers using JWKS public keys (RS256/ES256)
- **[MCP Integration Guide](docs/MCP.md)** - Resource Indicators (RFC 8707), AS metadata (RFC 8414), audience binding, CORS for browser-based MCP clients, multi-resource-server caveats
- **[JWT Verification Guide](docs/JWT_VERIFICATION.md)** - Verify tokens at resource servers using JWKS public keys (RS256/ES256), `aud` and `type` claim validation
- **[OAuth Setup Guide](docs/OAUTH_SETUP.md)** - GitHub, Gitea, Microsoft Entra ID integration
- **[Rate Limiting Guide](docs/RATE_LIMITING.md)** - Protect against brute force and API abuse
- **[Performance Guide](docs/PERFORMANCE.md)** - Scalability, optimization, benchmarks
Expand Down Expand Up @@ -342,31 +347,32 @@ sequenceDiagram

**Key Endpoints:**

| Endpoint | Method | Purpose |
| ----------------------------------- | -------- | ------------------------------------------------------------------------------------------ |
| `/.well-known/openid-configuration` | GET | OIDC Discovery metadata |
| `/.well-known/jwks.json` | GET | JWKS public keys for RS256/ES256 verification (RFC 7517) |
| `/oauth/device/code` | POST | Request device code (CLI) |
| `/oauth/authorize` | GET | Authorization consent page (web apps) |
| `/oauth/authorize` | POST | Submit consent decision |
| `/oauth/token` | POST | Token endpoint: `device_code`, `authorization_code`, `refresh_token`, `client_credentials` |
| `/oauth/tokeninfo` | GET | Verify token validity |
| `/oauth/userinfo` | GET/POST | OIDC UserInfo — profile claims for token owner |
| `/oauth/revoke` | POST | Revoke tokens ([RFC 7009][rfc7009]) |
| `/oauth/register` | POST | Dynamic client registration ([RFC 7591][rfc7591]) |
| `/oauth/introspect` | POST | Token introspection ([RFC 7662][rfc7662]) |
| `/device` | GET | Device code entry page (browser) |
| `/account/sessions` | GET | Manage active token sessions |
| `/account/authorizations` | GET | Manage per-app consent grants |
| `/admin/clients/:id/authorizations` | GET | Admin: view all authorized users for a client |
| `/admin/clients/:id/revoke-all` | POST | Admin: force re-auth for all users |
| `/admin/users` | GET/POST | Admin: list / create users |
| `/admin/users/:id/disable` | POST | Admin: disable user (revokes all tokens, blocks login) |
| `/admin/users/:id/enable` | POST | Admin: re-enable a disabled user |
| `/admin/users/:id/connections` | GET | Admin: list a user's third-party OAuth connections |
| `/admin/users/:id/authorizations` | GET | Admin: list apps a user has authorized |
| `/health` | GET | Health check |
| `/metrics` | GET | Prometheus metrics (optional auth) |
| Endpoint | Method | Purpose |
| ----------------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `/.well-known/openid-configuration` | GET | OIDC Discovery metadata |
| `/.well-known/oauth-authorization-server` | GET | OAuth 2.0 AS Metadata ([RFC 8414][rfc8414]) — required by MCP / RFC 8414-aware clients |
| `/.well-known/jwks.json` | GET | JWKS public keys for RS256/ES256 verification (RFC 7517) |
| `/oauth/device/code` | POST | Request device code (CLI). Accepts optional repeatable `resource` ([RFC 8707][rfc8707]) |
| `/oauth/authorize` | GET | Authorization consent page (web apps). Accepts optional repeatable `resource` |
| `/oauth/authorize` | POST | Submit consent decision |
| `/oauth/token` | POST | Token endpoint: `device_code`, `authorization_code`, `refresh_token`, `client_credentials`. Accepts optional `resource` (subset of the granted audience per RFC 8707 §2.2) |
| `/oauth/tokeninfo` | GET | Verify token validity |
| `/oauth/userinfo` | GET/POST | OIDC UserInfo — profile claims for token owner |
| `/oauth/revoke` | POST | Revoke tokens ([RFC 7009][rfc7009]) |
| `/oauth/register` | POST | Dynamic client registration ([RFC 7591][rfc7591]) |
| `/oauth/introspect` | POST | Token introspection ([RFC 7662][rfc7662]) |
| `/device` | GET | Device code entry page (browser) |
| `/account/sessions` | GET | Manage active token sessions |
| `/account/authorizations` | GET | Manage per-app consent grants |
| `/admin/clients/:id/authorizations` | GET | Admin: view all authorized users for a client |
| `/admin/clients/:id/revoke-all` | POST | Admin: force re-auth for all users |
| `/admin/users` | GET/POST | Admin: list / create users |
| `/admin/users/:id/disable` | POST | Admin: disable user (revokes all tokens, blocks login) |
| `/admin/users/:id/enable` | POST | Admin: re-enable a disabled user |
| `/admin/users/:id/connections` | GET | Admin: list a user's third-party OAuth connections |
| `/admin/users/:id/authorizations` | GET | Admin: list apps a user has authorized |
| `/health` | GET | Health check |
| `/metrics` | GET | Prometheus metrics (optional auth) |

**[Full API Reference →](docs/ARCHITECTURE.md#key-endpoints)** | **[Metrics Documentation →](docs/METRICS.md)**

Expand Down Expand Up @@ -690,8 +696,10 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
- [RFC 7591 - OAuth 2.0 Dynamic Client Registration Protocol][rfc7591]
- [RFC 7662 - OAuth 2.0 Token Introspection][rfc7662]
- [RFC 8414 - OAuth 2.0 Authorization Server Metadata][rfc8414]
- [RFC 8707 - Resource Indicators for OAuth 2.0][rfc8707]
- [RFC 9700 - Best Current Practice for OAuth 2.0 Security][rfc9700]
- [OpenID Connect Core 1.0][oidccore]
- [Model Context Protocol Specification][mcp-spec]

---

Expand Down Expand Up @@ -720,5 +728,7 @@ Built with:
[rfc7591]: https://datatracker.ietf.org/doc/html/rfc7591
[rfc7662]: https://datatracker.ietf.org/doc/html/rfc7662
[rfc8414]: https://datatracker.ietf.org/doc/html/rfc8414
[rfc8707]: https://datatracker.ietf.org/doc/html/rfc8707
[rfc9700]: https://datatracker.ietf.org/doc/html/rfc9700
[oidccore]: https://openid.net/specs/openid-connect-core-1_0.html
[mcp-spec]: https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization
28 changes: 27 additions & 1 deletion docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,8 @@ sequenceDiagram
| Endpoint | Method | Auth Required | Purpose |
| ---------------------------------------------- | -------- | ------------- | ------------------------------------------------------------------------------------------------- |
| `/health` | GET | No | Health check with database connection test |
| `/.well-known/openid-configuration` | GET | No | OIDC Discovery metadata (RFC 8414 / OIDC Discovery 1.0) |
| `/.well-known/openid-configuration` | GET | No | OIDC Discovery metadata (OIDC Discovery 1.0) |
| `/.well-known/oauth-authorization-server` | GET | No | OAuth 2.0 Authorization Server Metadata (RFC 8414) — required by MCP / RFC 8414-aware clients |
| `/.well-known/jwks.json` | GET | No | JWKS public keys for RS256/ES256 JWT verification (RFC 7517) |
| `/oauth/device/code` | POST | No | Request device and user codes (CLI/device) |
| `/oauth/authorize` | GET | Yes (Session) | Authorization Code Flow consent page (web apps) |
Expand Down Expand Up @@ -459,10 +460,35 @@ The application automatically creates these tables:
- `users` - User accounts (includes OAuth-linked users)
- `oauth_clients` - Registered client applications
- `device_codes` - Active device authorization requests
- `authorization_codes` - One-time authorization codes for the Authorization Code Flow
- `user_authorizations` - Per-user, per-application consent grants
- `access_tokens` - Issued JWT tokens (both access and refresh tokens)
- `oauth_connections` - OAuth provider connections (GitHub, Gitea, etc.)
- `audit_logs` - Comprehensive audit trail of all operations (authentication, tokens, admin actions, security events)

### RFC 8707 Resource Indicator Columns

The `device_codes`, `authorization_codes`, `user_authorizations`, and `access_tokens` tables each carry a nullable `Resource` JSON column (`StringArray`). GORM AutoMigrate adds this column on startup; existing rows have an empty `Resource`.

**Dual semantics on `access_tokens.Resource` (read carefully):**

| Token category | `Resource` column meaning |
| -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Access token | **Audience snapshot at issuance** — exactly what the JWT was signed with. RFC 7662 introspection reads this directly so `JWT_AUDIENCE` rotation cannot change what introspection reports for older tokens. |
| Refresh token | **The original grant's RFC 8707 resource set** — used for RFC 8707 §2.2 subset checks on subsequent refresh requests. **NOT** the refresh JWT's `aud` (refresh JWTs are signed with the static `JWT_AUDIENCE`, never the per-request resource). |

Any code reading `access_tokens.Resource` directly must branch on `TokenCategory` to interpret the value correctly.

### TokenProvider interface signature

The PR that introduced RFC 8707 support **changed the signature** of `core.TokenProvider`:

- `GenerateToken`, `GenerateRefreshToken`, `GenerateClientCredentialsToken` each gained a trailing `audience []string` parameter.
- `RefreshAccessToken` split its single `audience` parameter into `accessAudience, refreshAudience []string` so refresh JWTs never carry a per-request RS `aud`.
- A new `ValidateRefreshToken(ctx, tokenString) (*TokenValidationResult, error)` method is required for legacy-row audience recovery.

Any out-of-tree `core.TokenProvider` implementation must be updated to match. Pass `nil` for the new audience parameters to preserve pre-PR behaviour.

---

**Next Steps:**
Expand Down
Loading
Loading