Explore OAuth2 and OpenID Connect in Scala with emphasis on token validation, boundary ownership, and avoiding security mistakes around sessions, scopes, and audience checks.
OAuth2 is an authorization framework. OpenID Connect (OIDC) adds identity on top of OAuth2.
In Scala applications, the implementation challenge is rarely the raw protocol alone. It is deciding which part of the system owns login, token validation, refresh behavior, and downstream authorization checks.
At a minimum, be clear about:
The flow below shows a simple browser-facing OIDC login shape:
sequenceDiagram
participant Browser as "User Browser"
participant App as "Scala App"
participant IdP as "Identity Provider"
participant API as "Protected API"
Browser->>App: "Request protected page"
App->>IdP: "Redirect for login"
IdP-->>Browser: "Authenticate user"
IdP-->>App: "Authorization code"
App->>IdP: "Exchange code for tokens"
IdP-->>App: "ID token + access token"
App->>API: "Call API with access token"
API-->>App: "Authorized response"
The important thing to notice is that the application does not “trust the browser because login happened.” It trusts tokens only after validating the issuer, audience, expiry, and other relevant claims.
A valid-looking JWT is not enough. Services need to check the claims that actually matter:
Skipping audience or issuer checks is one of the easiest ways to create token confusion across services.
OAuth scopes are useful, but they do not automatically express every domain rule. Application-level authorization still needs to evaluate:
The access token gets the request to the right boundary. It does not eliminate local authorization decisions.
The app gets a token and assumes everything downstream is secure without validating the right claims.
Session cookies, refresh flows, and access-token validation are related but not interchangeable.
Different services often need different audience, scope, or token-validation rules.
Treat OAuth2 and OIDC as explicit trust boundaries. Validate tokens rigorously, keep identity proof separate from local authorization, and make service trust assumptions reviewable instead of burying them inside framework defaults.