From spring
Implement an OAuth2 or OpenID Connect provider with Spring Authorization Server including registered clients, PKCE authorization code, token issuance, JWK exposure, consent, PAR, device authorization, introspection, and revocation. Use this skill when implementing an OAuth2 or OpenID Connect provider with Spring Authorization Server, including registered clients, authorization code with PKCE, token issuance, JWK exposure, consent, PAR, device authorization, introspection, revocation, and provider configuration.
npx claudepluginhub ririnto/sinon --plugin springThis skill uses the workspace's default tool permissions.
Use this skill when implementing an OAuth2 or OpenID Connect provider with Spring Authorization Server, including registered clients, authorization code with PKCE, token issuance, JWK exposure, consent, PAR, device authorization, introspection, revocation, and provider configuration.
references/client-authentication-variants.mdreferences/deployment-and-operations.mdreferences/device-authorization-grant.mdreferences/dynamic-client-registration.mdreferences/endpoint-customization.mdreferences/extension-grants.mdreferences/federated-identity-and-social-login.mdreferences/introspection-and-revocation.mdreferences/jpa-persistence.mdreferences/migrate-spring-security-6-to-7.mdreferences/multitenancy.mdreferences/oidc-provider-endpoints.mdreferences/proof-of-possession-variants.mdreferences/pushed-authorization-requests.mdreferences/redis-persistence.mdreferences/testing-authorization-endpoint.mdreferences/testing-introspection-revocation-and-consent.mdreferences/testing-oidc-endpoints.mdreferences/testing-refresh-path.mdreferences/testing-token-metadata-and-jwk-endpoints.mdMandates invoking relevant skills via tools before any response in coding sessions. Covers access, priorities, and adaptations for Claude Code, Copilot CLI, Gemini CLI.
Share bugs, ideas, or general feedback.
Use this skill when implementing an OAuth2 or OpenID Connect provider with Spring Authorization Server, including registered clients, authorization code with PKCE, token issuance, JWK exposure, consent, PAR, device authorization, introspection, revocation, and provider configuration.
Use spring-authorization-server for provider-side OAuth2 or OIDC endpoints, token issuance, registered client configuration, JWK publication, authorization consent, and issuer configuration.
spring-security for application login, resource-server token validation, or ordinary web security that does not issue OAuth2 tokens.Use this map to keep the current stable Spring Authorization Server 1.5.x surface visible without pushing every protocol branch into references/. Spring Authorization Server is a standalone project that builds on Spring Security; version advice here targets the SAS artifact line (org.springframework.security:spring-security-oauth2-authorization-server), not Spring Security's release cadence.
| Surface | Start here when | Open a reference when |
|---|---|---|
| Core provider configuration | The server needs issuer, filter chains, signing keys, clients, and token issuance | Endpoint behavior changes beyond defaults in references/endpoint-customization.md |
| Authorization code with PKCE | One interactive client flow is enough for the first provider | Client authentication or proof-of-possession variants are the blocker in references/client-authentication-variants.md or references/proof-of-possession-variants.md |
| Token generation | Default JWT issuance needs only small claim customization | Token format, claim mapping, or token-generator composition are the blocker in references/token-generation-and-customization.md |
| OIDC provider endpoints | The provider must act as an identity provider, not only an OAuth2 server | Discovery, UserInfo, logout, or ID-token behavior are the blocker in references/oidc-provider-endpoints.md |
| PAR and advanced request entry | Clients must pre-register authorization parameters at the server | Pushed Authorization Request behavior is the blocker in references/pushed-authorization-requests.md |
| Device authorization flow | The client cannot drive a browser redirect flow directly | Device authorization and verification are the blocker in references/device-authorization-grant.md |
| Introspection and revocation | Relying parties or resource servers need token liveness checks or revocation | Introspection or revocation endpoint behavior is the blocker in references/introspection-and-revocation.md |
| Dynamic client registration | External clients must self-register | Registration security and metadata mapping are the blocker in references/dynamic-client-registration.md |
| Federation and social login | User authentication comes from an external identity provider | Federated login behavior is the blocker in references/federated-identity-and-social-login.md |
| Extension grants | Built-in grant types do not cover the protocol | Custom grant converters and providers are the blocker in references/extension-grants.md |
| Persistence | In-memory repositories are no longer enough | Relational or Redis-backed state is the blocker in references/jpa-persistence.md or references/redis-persistence.md |
| Multitenancy | One host must serve multiple issuers or tenant-scoped clients | Issuer-scoped component delegation is the blocker in references/multitenancy.md |
| Deployment and testing | The server is moving to production or needs deeper flow verification | Operational hardening is the blocker in references/deployment-and-operations.md, deeper authorization-endpoint tests are the blocker in references/testing-authorization-endpoint.md, token, metadata, and JWK endpoint tests are the blocker in references/testing-token-metadata-and-jwk-endpoints.md, OIDC endpoint tests are the blocker in references/testing-oidc-endpoints.md, refresh-path tests are the blocker in references/testing-refresh-path.md, and introspection, revocation, or consent tests are the blocker in references/testing-introspection-revocation-and-consent.md |
The ordinary Spring Authorization Server job is:
SecurityFilterChain and one ordinary login SecurityFilterChain for user authentication.UserDetailsService, one RegisteredClientRepository, one JWKSource, one JwtDecoder, and one AuthorizationServerSettings bean.Use the Boot starter for the ordinary authorization-server path and add test support for endpoint verification.
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-authorization-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
The minimum provider needs these components wired intentionally:
SecurityFilterChain for authorization-server endpointsUserDetailsService for the user who approves or denies authorizationRegisteredClientRepository for OAuth client registrationJWKSource<SecurityContext> for signing keysJwtDecoder for JWT-backed endpoint processingAuthorizationServerSettings for issuer and endpoint settingsKeep the core model vocabulary explicit:
| Type | Role |
|---|---|
RegisteredClient | client registration: redirect URIs, scopes, grant types, auth method, token settings |
OAuth2Authorization | active authorization state and issued-token linkage |
OAuth2AuthorizationConsent | user-approved scopes for a client |
| authenticated principal | the end user who signs in and authorizes the request |
@Bean
@Order(1)
SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
http.oauth2AuthorizationServer(authorizationServer -> http.securityMatcher(authorizationServer.getEndpointsMatcher()));
return http.exceptionHandling(exceptions -> exceptions.defaultAuthenticationEntryPointFor(new LoginUrlAuthenticationEntryPoint("/login"), new MediaTypeRequestMatcher(MediaType.TEXT_HTML))).build();
}
@Bean
@Order(2)
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
return http.authorizeHttpRequests(authorize -> authorize.anyRequest().authenticated())
.formLogin(Customizer.withDefaults())
.build();
}
@Bean
AuthorizationServerSettings authorizationServerSettings() {
return AuthorizationServerSettings.builder().issuer("http://auth-server:9000").build();
}
Keep the issuer explicit and stable. Add .oidc(Customizer.withDefaults()) only when the provider must expose OIDC endpoints. Keep the login-side chain separate from issuer-side endpoint configuration.
@Bean
UserDetailsService users() {
UserDetails user = User.withUsername("user")
.password("{noop}password")
.roles("USER")
.build();
return new InMemoryUserDetailsManager(user);
}
@Bean
JwtDecoder jwtDecoder(JWKSource<SecurityContext> jwkSource) {
return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource);
}
@Bean
RegisteredClientRepository registeredClientRepository() {
RegisteredClient publicClient = RegisteredClient.withId(UUID.randomUUID().toString())
.clientId("messaging-client")
.clientAuthenticationMethod(ClientAuthenticationMethod.NONE)
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
.redirectUri("http://127.0.0.1:8080/login/oauth2/code/messaging-client")
.scope("message.read")
.clientSettings(ClientSettings.builder().requireProofKey(true).build())
.build();
return new InMemoryRegisteredClientRepository(publicClient);
}
Start with one registered client and one interactive flow. Default to a public client with PKCE unless the client can truly protect a secret on the server side.
@Bean
JWKSource<SecurityContext> jwkSource() {
RSAKey rsaKey = generateRsa();
JWKSet jwkSet = new JWKSet(rsaKey);
return (selector, securityContext) -> selector.select(jwkSet);
}
Keep signing keys centralized and intentional. Move key loading, rotation, and external key-management decisions into deployment-specific work only after the baseline server is correct.
@Bean
OAuth2TokenCustomizer<JwtEncodingContext> jwtCustomizer() {
return context -> {
if (OAuth2TokenType.ACCESS_TOKEN.equals(context.getTokenType())) {
context.getClaims().claim("tenant", "default");
}
};
}
Keep the customizer small and deterministic. Add claims only when a downstream resource server or client actually depends on them.
Treat the endpoint surface as part of the provider contract.
authorization: /oauth2/authorize
token: /oauth2/token
metadata: /.well-known/oauth-authorization-server
jwk set: /oauth2/jwks