Databases, Spring and microservices · 4. Spring Security, lesson 7 of 8

OAuth 2.0 and OpenID Connect: social login, Keycloak and resource servers

Advanced3 min read@since 17Code runs on your Java 25
Explain it forThe essentials plus production detail and pitfalls.

OAuth 2.0 is a standard for delegated authorization: an app gets a token to access resources on a user's behalf, without ever seeing the user's password. OpenID Connect (OIDC) adds authentication on top: an ID token (a JWT) that says who the user is.

The four roles: the resource owner (the user), the client (your app), the authorization server (Google, Microsoft, Okta, Keycloak, Spring Authorization Server) and the resource server (your API, which accepts the access tokens).

Which flow:

  • Authorization code with PKCE: web apps, mobile apps and single-page apps. The standard choice.
  • Client credentials: service-to-service calls with no user.
  • Device code: TVs and CLIs.
  • The old implicit and password grants are deprecated; don't use them.

In Spring Boot:

  • Login with an identity provider: spring-boot-starter-oauth2-client plus .oauth2Login().
  • An API that accepts tokens: spring-boot-starter-oauth2-resource-server plus an issuer-uri. Spring discovers the provider's public keys (JWKS) and validates every token.
  • Keycloak is a popular self-hosted authorization server: users, roles, social login and MFA without writing them yourself.
Diagram

Example

Java
@Bean
SecurityFilterChain security(HttpSecurity http) throws Exception {
    return http
        .authorizeHttpRequests(auth -> auth
            .requestMatchers("/", "/public/**").permitAll()
            .anyRequest().authenticated())
        .oauth2Login(Customizer.withDefaults())             // "Log in with Google" for the web app
        .build();
}

@GetMapping("/me")
Map<String, Object> me(@AuthenticationPrincipal OidcUser user) {
    return Map.of(
        "name", user.getFullName(),                     // claims from the ID token
        "email", user.getEmail(),
        "verified", user.getEmailVerified());
}
application.properties for both sides
# The web app logs users in with Google (OAuth2 client / OIDC login)
spring.security.oauth2.client.registration.google.client-id=${GOOGLE_CLIENT_ID}
spring.security.oauth2.client.registration.google.client-secret=${GOOGLE_CLIENT_SECRET}
spring.security.oauth2.client.registration.google.scope=openid,email,profile

# The API accepts access tokens issued by Keycloak (resource server)
spring.security.oauth2.resourceserver.jwt.issuer-uri=https://auth.javaatlas.com/realms/javaatlas

Common mistake

Treating an access token as proof of who the user is. Use the ID token (OIDC) for identity; access tokens are for calling APIs and may not even be readable by the client.

Under the hood

A resource server must check more than the signature: the issuer (iss), the audience (aud: was this token meant for this API?) and expiry. Spring checks iss and exp from the issuer-uri; add an audience validator for aud. For single-page apps, the most secure setup is a backend-for-frontend: the server does the OAuth flow and keeps tokens, and the browser only holds an HttpOnly session cookie.

Check yourself

What does PKCE protect against?

How this connects

Where this leads

You've reached the end of this thread. Try a learning path for what's next.

Part of Spring Core and Spring Security in depth.

Was this lesson helpful?

Finished reading? Mark it complete to track your progress.