[Server] Add native OAuth 2.1 authorization server#373
Conversation
Adds a self-contained OAuth 2.1 authorization-server layer to the HTTP server transport, complementing the existing resource-server/proxy support so an MCP server can issue and validate its own access tokens without an external IdP or a third-party OAuth library. - Engine behind interfaces (AuthorizationCodeIssuerInterface, TokenGranterInterface) with native implementations: authorization code grant with mandatory PKCE S256, refresh-token rotation, one-time codes. - RS256 JWT access tokens (JwtAccessTokenIssuer) that validate through the existing JwtTokenValidator; RsaSigningKey + JWKS publishing; StaticJwksProvider for in-process self-validation. - Storage interfaces (clients, authorization codes, refresh tokens, optional access tokens) with in-memory and PSR-16 implementations. - RFC 8414 AuthorizationServerMetadata, RFC 7591 StoredClientRegistrar, and the AuthorizationEndpoint/Token/AuthorizationServerMetadata/Jwks middlewares. - Host seams: ResourceOwnerResolverInterface and ConsentInterface (+ default AutoApproveConsent). - OAuthException for RFC 6749 error responses, plus a runnable example. Signing uses firebase/php-jwt (already used by JwtTokenValidator); no new hard dependency.
|
I don't think we want to have anative oAuth server in this SDK it's way out of scope. We need to document this properly as it's easy added using an outside oAuth2 library component. IMO this subject is just like the JSON Schema we should probably ship a default library and give extension points if needed to use other libraries. |
|
Closing in favour of ADR 0001 (#382): the SDK is an OAuth Resource Server (+ delegation), not an authorization server. Agreed — issuing tokens/keys/consent shouldn't live here. The authorization-server need it addressed will be pursued where the ADR points — Thanks @soyuka for the clear scope ruling. |
Summary
The HTTP server transport already supports being an OAuth resource server (validating tokens) and an OAuth proxy to an upstream IdP. This adds the missing third piece: a self-contained OAuth 2.1 authorization server, so an MCP server can register clients, authorize users, and issue + validate its own RS256 JWT access tokens — without an external IdP or a third-party OAuth library (e.g.
league/oauth2-server).It is dependency-free apart from
firebase/php-jwt, which the existingJwtTokenValidatoralready uses for validation; signing reuses it. No new hard dependency.What's included (
src/Server/Transport/Http/)AuthorizationCodeIssuerInterface/TokenGranterInterfacewithNative*implementations: authorization code grant with mandatory PKCE (S256), refresh-token rotation, one-time short-TTL codes, exactredirect_urimatching, constant-time client auth.JwtAccessTokenIssuer(RS256) producing tokens that validate unchanged through the existingJwtTokenValidator;RsaSigningKey,JwksMiddleware, andStaticJwksProviderfor in-process self-validation (no network round-trip).AuthorizationEndpointMiddleware,TokenEndpointMiddleware,AuthorizationServerMetadataMiddleware(RFC 8414); DCR (RFC 7591) viaStoredClientRegistrar+ the existingClientRegistrationMiddleware.ClientRepositoryInterface,AuthorizationCodeStoreInterface,RefreshTokenStoreInterface, optionalAccessTokenStoreInterface, each with in-memory and PSR-16 implementations.ResourceOwnerResolverInterface(the SDK can't authenticate users) andConsentInterface(+ defaultAutoApproveConsent).OAuthExceptionfor RFC 6749 §5.2 error responses.examples/server/oauth-authorization-server/.The engine is transport-agnostic (the middlewares are thin PSR-7 shells over it), so it can be driven directly from a framework controller too.
Tests
144 new unit tests (PKCE RFC 7636 vector, self-issued round-trip through
JwtTokenValidator, granter behaviours, registrar, metadata, middlewares). phpstan level 6 clean.Status
Draft. This is the SDK half of a larger effort to let Symfony MCP servers act as their own OAuth AS. Companion work, built on these primitives and validated end-to-end against a real Sulu MCP server:
Feedback on the public API/seams welcome.