Bearer Token

 Let’s walk through a concrete scenario step by step—an e-commerce app where a mobile client talks to two services: an Auth Service (issues tokens) and an Order Service (protects endpoints).


1. User Logs In and Gets a Bearer Token

Request to Auth Service

POST https://auth.myshop.com/login
Content-Type: application/json

{
  "username": "alice@example.com",
  "password": "P@ssw0rd!"
}

Response from Auth Service

HTTP/1.1 200 OK
Content-Type: application/json

{
  "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."
  "token_type": "Bearer",
  "expires_in": 3600,
  "scope": "orders:read orders:write"
}
  • access_token is a JWT (JSON Web Token).

  • The client stores it (e.g. in memory or secure storage).


2. Client Calls a Protected Endpoint

Alice’s app now wants to fetch her orders:

GET https://api.myshop.com/orders
Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...
  • Note the header: Authorization: Bearer <token>.


3. Order Service Validates the Token

Under the hood, Spring Security’s Resource Server filter chain does this automatically:

  1. Extract the token from the Authorization header.

  2. Decode & Verify Signature

    • Fetch the public keys from the Auth Service’s JWK endpoint (e.g. https://auth.myshop.com/.well-known/jwks.json).

    • Use them to verify the JWT’s cryptographic signature—ensures it really came from your Auth Service.

  3. Check Standard Claims

    • exp (expiration): reject if expired.

    • aud (audience): must match “api.myshop.com”.

    • iss (issuer): must be “https://auth.myshop.com”.

  4. Populate Security Context

    • Extract scopes (e.g. orders:read) from the JWT’s scope claim.

    • Map them to Spring authorities (e.g. SCOPE_orders:read).

  5. Authorize the Request

    • Your HttpSecurity config says .antMatchers("/orders").hasAuthority("SCOPE_orders:read").

    • If Alice’s token has that scope, the call proceeds. Otherwise, she gets 403 Forbidden.


4. Order Service Responds

HTTP/1.1 200 OK
Content-Type: application/json

[
  { "orderId": 123, "total": 49.95, … },
  { "orderId": 124, "total": 19.99, … }
]

Alice sees her order list. All without ever sending username/password again—just the bearer token.


Key Points

  • Bearer means “anyone holding this token can use it.” Keep it secret!

  • JWTs are self-contained: you don’t need a database lookup on each request (just key lookup).

  • Validation = signature check + claim checks (+ optional revocation or introspection).

  • Spring Security’s resource-server support wires all this up with just a few lines of config.


Spring Security Config Snippet

@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
  http
    .authorizeHttpRequests(auth -> auth
      .requestMatchers("/orders").hasAuthority("SCOPE_orders:read")
      .anyRequest().authenticated()
    )
    .oauth2ResourceServer(oauth2 -> oauth2
      .jwt(jwt -> jwt
        .jwkSetUri("https://auth.myshop.com/.well-known/jwks.json")
      )
    );
  return http.build();
}
  • .oauth2ResourceServer().jwt() turns on JWT validation.

  • .jwkSetUri(...) tells Spring where to fetch your Auth Service’s public keys.


This end-to-end flow—from login to token validation on each request—is the essence of using bearer tokens in real systems.

Comments