OAuth 2.0 and OpenID Connect (OIDC) are powerful, flexible, and… surprisingly easy to misconfigure.
Note: This article belongs to Part 5.2: App Security Best Practices in our Application Security series.
From overly permissive tokens to incorrect redirect URIs and unchecked ID tokens — even mature teams fall into subtle traps. In this final post of our Application Security series, we’ll look at the most common OAuth/OIDC mistakes developers and architects make, what goes wrong under the hood, and how to do it right — especially when working with Spring Security.
Let’s secure your setup before your pen test does.

🧨 1. Misconfigured Redirect URIs
❌ What Goes Wrong
- Wildcard redirect URIs (e.g.,
https://yourapp.com/*
) - Open redirect vulnerabilities via query manipulation
- Redirects pointing to non-production domains or external sites
⚠️ Risk
- Attackers can hijack the auth code and steal tokens via malicious redirect endpoints.
✅ What to Do
- Always whitelist exact redirect URIs on your Identity Provider (IdP).
- Avoid dynamic manipulation of
redirect_uri
via query params. - In Spring Security:
oauth2Login() .redirectionEndpoint() .baseUri("/oauth2/callback/*"); // be specific
🔓 2. Not Verifying ID Token or Access Token
❌ What Goes Wrong
- Trusting tokens without validating their signature, issuer, or audience
- Skipping nonce validation in OIDC flows
⚠️ Risk
- Accepting forged or tampered tokens from untrusted sources.
✅ What to Do
- Always validate:
iss
(issuer)aud
(audience)exp
(expiry)- Token signature via JWKS
- In Spring Security, most of this is done if you configure the JWT decoder correctly:
.oauth2ResourceServer() .jwt() .jwkSetUri("https://example.com/.well-known/jwks.json")
🔐 3. Storing Tokens in Local Storage
❌ What Goes Wrong
- Storing tokens (especially refresh tokens) in
localStorage
orsessionStorage
⚠️ Risk
- Vulnerable to Cross-Site Scripting (XSS) — attackers can steal tokens from browser storage.
✅ What to Do
- Prefer using HttpOnly, Secure cookies for token storage.
- Or better yet, use a Backend-for-Frontend (BFF) pattern to manage tokens safely on the server side.
🔄 4. Not Using PKCE in Public Clients
❌ What Goes Wrong
- SPAs and mobile apps using Authorization Code flow without PKCE
⚠️ Risk
- Code interception attack: an attacker can steal the auth code and exchange it for a token.
✅ What to Do
- Always use PKCE (
code_challenge
+code_verifier
) in public clients. - Spring Security handles this out-of-the-box with
oauth2Login()
since Spring Security 5.2+.
📡 5. Too Broad or Undefined Scopes
❌ What Goes Wrong
- Apps request
openid profile email
when onlyemail
is needed - APIs issue access tokens with
"scope": "read write delete *"
by default
⚠️ Risk
- Excessive privileges violate least privilege principle; if a token is compromised, more damage is possible.
✅ What to Do
- Explicitly define and request minimal scopes needed.
- Scope policies should be reviewed regularly.
- In Spring Security, configure scope validation for resource server endpoints:
.authorizeHttpRequests() .requestMatchers("/admin/**").hasAuthority("SCOPE_admin")
🧪 6. Mixing Up Access Tokens and ID Tokens
❌ What Goes Wrong
- Using an ID token (meant for login identity) to authorize API access
- Sending ID tokens to APIs
⚠️ Risk
- ID tokens are not meant to be validated by resource servers. APIs might trust unverified data.
✅ What to Do
- Access tokens go to APIs; ID tokens stay in the frontend or app logic.
- Never send ID tokens to backend services.
🧯 7. Skipping Token Expiry & Refresh Handling
❌ What Goes Wrong
- Not handling
401 Unauthorized
responses - Not using refresh tokens at all
⚠️ Risk
- Users get logged out unexpectedly, or your app keeps trying to use expired tokens.
✅ What to Do
- Implement a token refresh strategy with retry logic.
- For SPAs or mobile apps, use a BFF or silent refresh via iframe/token endpoint.
- In Spring, handle token expiry in filters or custom handlers.
🧰 Bonus: Spring Security Tips
- Set your token audience check manually if needed:
.jwtAuthenticationConverter(customJwtAuthenticationConverter());
- Customize token introspection if you’re using opaque tokens:
.oauth2ResourceServer() .opaqueToken() .introspectionUri(...)
Conclusion
OAuth and OIDC are battle-tested protocols — but they’re only as secure as their configuration.
Whether you’re securing a SPA, a mobile app, or a backend-for-frontend architecture, the difference between “it works” and “it’s secure” lies in the details. By avoiding these common misconfigurations, you’re not just patching holes — you’re designing trust.
What’s Next?
🎉 That’s a wrap on our Application Security Series!
If you’ve followed us from the basics of identity to token handling and security best practices — give yourself a high-five. Missed a post? You can catch up on the full series here.
Have a Question?
Hit a wall trying to debug a token issue? Confused by a provider-specific config? Drop a comment — always happy to help.