OAuth 2.0 / OIDC for Spring Boot microservices using PingFederate
1) Big picture
[Browser / Mobile / SPA]
| (Auth Code + PKCE)
v
+------------------------+ (JWT or opaque access tokens)
| PingFederate (AS) | ---> [JWKS endpoint / Introspection]
| /as/authorization... | /pf/JWKS /as/introspect.oauth2
| /as/token.oauth2 |
| /.well-known/openid...|
+-----------+------------+
|
| (Bearer token on API calls)
v
[API Gateway]* ← optional central policy & caching
|
+------+------+
| Spring Boot| (Resource Servers)
| microservices
+------+------+
|
[Data/Domain]
Why this shape?
- For user-facing apps, use Authorization Code + PKCE; PingFederate publishes discovery metadata and supports
S256
PKCE. (Ping Identity Docs) - For service-to-service, use Client Credentials.
- For high TPS, prefer JWT access tokens and local validation via JWKS (no per-request network hop); fall back to opaque tokens + introspection only when you need immediate revocation or rich token lookups. PingFederate exposes well-known OIDC metadata (issuer, JWKS), authorization and token endpoints, and an OAuth Introspection endpoint. (Ping Identity Docs)
2) PingFederate endpoints you’ll use
-
Authorization:
https://<pf-host>:9031/as/authorization.oauth2
-
Token:
https://<pf-host>:9031/as/token.oauth2
-
Discovery (OIDC):
https://<pf-host>:9031/.well-known/openid-configuration
(containsissuer
,jwks_uri
,introspection_endpoint
, etc.; example showsjwks_uri: https://<pf-host>:9031/pf/JWKS
andintrospection_endpoint: /as/introspect.oauth2
). (Ping Identity Docs)
3) Token strategy (choose one per environment)
A. Signed JWT access tokens (recommended for scale)
-
Spring services validate tokens offline using
jwks_uri
from discovery. This avoids a call to PF on every request and scales linearly with CPU. Spring Security auto-configures this fromissuer-uri
. (Home)
B. Opaque tokens + introspection (revocation-friendly)
-
Services call PingFederate
/as/introspect.oauth2
(POST,application/x-www-form-urlencoded
) with client auth to checkactive
,scope
,exp
, etc. Higher latency; cache results at gateway if needed. (Ping Identity Docs)
4) Spring Boot configs
4.1 Resource Server — JWT (zero PF hop per request)
# application.yml
spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: https://<pf-host>:9031 # Spring discovers jwks_uri automatically
Spring will resolve discovery → JWKS and verify signatures locally. (Home)
HTTP security & scope→role mapping
@Configuration
@EnableMethodSecurity
class SecurityConfig {
@Bean
SecurityFilterChain api(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/actuator/**").permitAll()
.requestMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.oauth2ResourceServer(oauth -> oauth
.jwt(jwt -> jwt.jwtAuthenticationConverter(grantedAuthorities()))
);
return http.build();
}
private Converter<Jwt, ? extends AbstractAuthenticationToken> grantedAuthorities() {
var delegate = new JwtGrantedAuthoritiesConverter();
delegate.setAuthorityPrefix("ROLE_");
delegate.setAuthoritiesClaimName("scope"); // or "scp" / custom claim mapped in PF
return new JwtAuthenticationConverter() {{
setJwtGrantedAuthoritiesConverter(delegate);
}};
}
}
Map whatever PF places scopes/roles into (e.g.,
scope
,groups
, custom claims via attribute mapping on the PF side).
4.2 Resource Server — Opaque token introspection
spring:
security:
oauth2:
resourceserver:
opaque-token:
introspection-uri: https://<pf-host>:9031/as/introspect.oauth2
client-id: api-resource
client-secret: ${INTROSPECTION_SECRET}
PingFederate’s standard introspection endpoint returns active
, scope
, and other attributes; beware the added network cost. (Ping Identity Docs)
5) Browser / SPA flow (Auth Code + PKCE)
- App fetches discovery, redirects user to PF authorization endpoint with
code_challenge=S256
. - Backend exchanges
code
at token endpoint foraccess_token
(+id_token
if OIDC). - App calls your APIs with the access token; services validate JWT locally or introspect if opaque.
PingFederate’s discovery shows PKCE methods and all core URLs needed. (Ping Identity Docs)
Security tips
- Always use PKCE (S256) for public clients.
- Keep access tokens short-lived (e.g., 5–10 min) and rotate refresh tokens. (PF supports refresh tokens via standard token endpoint.) (Ping Identity Docs)
6) Service-to-service flow (Client Credentials)
- Register a PF client with client_credentials.
- Caller obtains token from /as/token.oauth2 and calls your APIs.
- Resource servers validate JWT via JWKS or introspect opaque tokens. (Ping Identity Docs)
7) Gateway & high-TPS hardening (optional but useful)
- Central validation: If you run an API gateway, do JWT verification once at the edge; pass a stripped verified identity context to services.
-
Introspection caching: If you must use opaque tokens, gateway can cache
active
responses briefly (e.g., TTL = remainingexp
or a few seconds) to cut PF round-trips. - Clock skew: Allow small skew (±60s) in Spring validation to avoid intermittent 401s during key rotation.
-
Key rotation: PF exposes
jwks_uri
—Spring will re-fetch as needed; ensure egress to PF for JWKS. (Ping Identity Docs)
8) Claims & authorization design
-
Scopes: Issue business scopes from PF (e.g.,
orders.read
,orders.write
) and gate APIs with@PreAuthorize("hasAuthority('SCOPE_orders.read')")
. -
Roles/Groups: Map directory groups → custom claim (e.g.,
roles
) in PF, then convert toROLE_*
in Spring (converter above). - Audiences: Use PF Access Token Manager audience/resource settings so tokens are audience-scoped to your APIs. (Ping Identity Docs)
9) Observability & ops
- Metrics: 401/403 rates, token validation latency, cache hit rate (if introspecting), PF endpoint p50/p95.
-
Tracing: Propagate
traceId
through gateway and services. - HA PF: Run PF behind LB with sticky session only if you use PF session pages; OIDC flows themselves are stateless.
-
Discovery health: Periodically check
/.well-known/openid-configuration
and JWKS reachability. (Ping Identity Docs)
10) Quick “copy-paste” checklist
- Decide JWT vs Opaque; prefer JWT + JWKS for high TPS. (Home)
-
Configure Spring Boot Resource Server with
issuer-uri
(JWT) orintrospection-uri
(opaque). (Home, Ping Identity Docs) - For browser apps, use Auth Code + PKCE (S256). (Ping Identity Docs)
- Know your PF endpoints: /as/authorization.oauth2, /as/token.oauth2, /.well-known/openid-configuration, /pf/JWKS, /as/introspect.oauth2. (Ping Identity Docs)
-
Map scopes/roles in PF attribute mapping → Spring
GrantedAuthorities
. - Set short token TTLs; rely on refresh tokens where needed (back-channel only). (Ping Identity Docs)
If you want, I can tailor this to your exact topology (gateway/no gateway, JWT vs opaque), and hand you ready-to-run Spring Boot starter modules (JWT and Introspection variants) with minimal code.