angular-oauth2-oidc is the de facto OAuth2 and OpenID Connect client library for Angular single-page apps, and using it safely comes down to picking the authorization code flow with PKCE, validating ID tokens properly, and being deliberate about where you store tokens. Maintained by Manfred Steyer, the package tracks Angular's release cadence closely; the current major line sits at version 22.x, and it pulls hundreds of thousands of weekly downloads, so a lot of production auth runs through it.
This guide covers how the library works, the settings that matter for security, and the mistakes that turn a working login into a session-hijack risk.
What angular-oauth2-oidc actually does
The library gives you an OAuthService that handles the browser side of the OpenID Connect protocol: redirecting the user to your identity provider, receiving the callback, exchanging the authorization code for tokens, validating the ID token, and keeping the access token fresh. It supports discovery via the provider's .well-known/openid-configuration document, which means you configure an issuer URL and the library learns the authorization, token, and JWKS endpoints from there.
You install it the usual way:
npm install angular-oauth2-oidc
A minimal, security-conscious configuration looks like this:
import { AuthConfig } from 'angular-oauth2-oidc';
export const authConfig: AuthConfig = {
issuer: 'https://id.example.com/realms/app',
redirectUri: window.location.origin + '/callback',
clientId: 'web-spa',
responseType: 'code',
scope: 'openid profile email',
useSilentRefresh: false,
showDebugInformation: false,
};
The responseType: 'code' line is the single most important choice here, and it is worth explaining why.
Use the code flow with PKCE, not implicit
Older Angular OAuth2 tutorials used the implicit flow, where the access token comes back directly in the URL fragment. The OAuth2 Security Best Current Practice (RFC 9700) deprecates implicit flow for browser apps because tokens end up in browser history, referrer headers, and logs. angular-oauth2-oidc supports the authorization code flow with PKCE (Proof Key for Code Exchange), which is what you should use for any new Angular OIDC OAuth2 setup.
Enable it explicitly:
this.oauthService.configure(authConfig);
this.oauthService.loadDiscoveryDocumentAndTryLogin().then(() => {
if (!this.oauthService.hasValidAccessToken()) {
this.oauthService.initCodeFlow();
}
});
Calling initCodeFlow() (rather than the old initImplicitFlow()) triggers PKCE automatically. The library generates a code verifier, sends only its hash to the authorization endpoint, and completes the exchange with the verifier. An attacker who intercepts the authorization code cannot redeem it without the verifier, which closes the code-interception attack that plain code flow is vulnerable to in a public client.
Validate the ID token, don't just decode it
An ID token is a signed JWT that asserts who the user is. Decoding it tells you the claims; validating it tells you whether to trust them. angular-oauth2-oidc validates the signature against the provider's JWKS and checks the standard claims when you provide the right config, but there are two settings people get wrong.
First, keep clock-skew tolerance tight. The clockSkewInSec option defaults are generous; do not inflate it to paper over a misconfigured server clock, because a wide window weakens exp and nbf enforcement. Second, if you set strictDiscoveryDocumentValidation to false to work around a non-compliant provider, understand you have turned off a real check. Prefer fixing the provider metadata.
The angular oauth2 token validation also depends on the jwks being reachable and fresh. The library caches keys; if your provider rotates signing keys, make sure discovery reloads so validation does not fail closed in a way that logs users out unexpectedly.
Where to store tokens
By default the library stores tokens in sessionStorage. Both localStorage and sessionStorage are readable by any JavaScript running on the page, which means a single cross-site scripting flaw exposes the tokens. There is no fully XSS-proof storage for a pure SPA, so the realistic defense is layered:
- Prefer
sessionStorageoverlocalStorageso tokens die when the tab closes. - Ship a strict Content-Security-Policy to shrink your XSS attack surface.
- Keep access-token lifetimes short and rely on refresh, so a stolen token has a small window.
- If your architecture allows it, consider the backend-for-frontend pattern where refresh tokens live in an HttpOnly cookie on your own server and never reach JavaScript.
XSS is the dominant threat to browser-based auth, and a static analysis or SCA workflow that flags a vulnerable transitive dependency pulling untrusted markup into the DOM is part of keeping that surface small.
Silent refresh and token renewal
To keep a session alive without bouncing the user through a full login, the library offers silent refresh via a hidden iframe and, more modern, refresh tokens with the code flow. Third-party-cookie restrictions in current browsers have made iframe-based silent refresh unreliable, so angular oidc oauth2 deployments increasingly use rotating refresh tokens instead. Configure the provider to issue them and let the library call the token endpoint when the access token nears expiry.
Watch two things: enable refresh-token rotation on the provider so a leaked refresh token is single-use, and handle the refresh failure path by sending the user to a clean re-login rather than looping.
Logout that actually ends the session
logOut() clears the local token store, but a real logout should also end the session at the identity provider so the next login is not silently re-authenticated. angular-oauth2-oidc supports RP-initiated logout by redirecting to the provider's end_session_endpoint with an ID-token hint. Wire that up, and set a postLogoutRedirectUri you control, or users appear logged out in your app while their provider session stays open.
FAQ
Is angular-oauth2-oidc still maintained?
Yes. The angular-oauth2-oidc npm package tracks Angular major releases, with the current line at version 22.x and regular publishes. It remains the most widely adopted OAuth2/OIDC client in the Angular ecosystem.
Should I use implicit flow or code flow with PKCE?
Code flow with PKCE. Implicit flow is deprecated by current OAuth2 security guidance because it exposes tokens in the URL. Call initCodeFlow() and the library handles PKCE for you.
Where should tokens be stored?
sessionStorage is the safer default of the browser options, but no browser storage resists XSS fully. Pair it with a strict CSP, short token lifetimes, and ideally a backend-for-frontend that keeps refresh tokens in HttpOnly cookies.
How do I keep dependencies like this secure over time?
Pin versions, watch advisories for the library and its transitive dependencies, and run automated scanning in CI. An SCA tool such as Safeguard can flag a vulnerable transitive package before it ships. See our SCA product and the Academy for deeper walkthroughs.