OAuth 2.0 is an authorization framework that allows third-party applications to access user resources without exposing credentials. It defines roles, flows, and token types used across modern Java applications.

Roles

Role Description
Resource Owner The user
Client Application requesting access
Authorization Server Issues tokens
Resource Server Hosts protected resources (API)

Token Types

Token Purpose Lifetime
Access Token API authorization Short (minutes–hours)
Refresh Token Obtain new access tokens Long (days–weeks)
ID Token (OIDC) User identity claims Short

Authorization Flows

  1. Client redirects user to Authorization Server
2. User authenticates and grants consent
3. Server redirects back with authorization code
4. Client exchanges code for access token (server-side)
5. Client calls Resource Server with access token
  

Client Credentials (service-to-service)

  1. Client sends client_id + client_secret to token endpoint
2. Authorization Server returns access token
3. Client calls Resource Server
  

No user involved — for machine-to-machine communication.

PKCE (for SPAs and mobile)

Extension of Authorization Code flow preventing code interception:

  1. Client generates code_verifier + code_challenge
2. Sends code_challenge with authorization request
3. Exchanges code + code_verifier for token
  

Spring Authorization Server

  <dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-oauth2-authorization-server</artifactId>
</dependency>
  
  @Bean
public RegisteredClient registeredClient() {
    return RegisteredClient.withId(UUID.randomUUID().toString())
        .clientId("my-client")
        .clientSecret("{bcrypt}$2a$10$...")
        .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
        .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
        .authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
        .redirectUri("http://localhost:8080/login/oauth2/code/my-client")
        .scope("read")
        .scope("write")
        .build();
}
  

Token Endpoint Request

  curl -X POST https://auth.example.com/oauth2/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials" \
  -d "client_id=my-service" \
  -d "client_secret=secret" \
  -d "scope=read write"
  

Response:

  {
  "access_token": "eyJhbGciOiJSUzI1NiIs...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "scope": "read write"
}
  

Scopes

Scopes limit what a token can access:

  read:users    — read user data
write:orders  — create/update orders
admin         — full access
  

Resource servers validate scopes before granting access.

Best Practices

  • Use Authorization Code + PKCE for all user-facing clients
  • Use Client Credentials for service-to-service communication
  • Keep access tokens short-lived; use refresh tokens for renewal
  • Never expose client secrets in frontend code
  • Validate token audience (aud) and issuer (iss) on resource servers
  • Use established providers (Keycloak, Auth0) rather than building from scratch