Tokens in the Browser: The Implicit Flow
One of the core objectives of OAuth 2 and OIDC is to accommodate as broad a range of client types as possible. This includes not only SPAs but also conventional web apps, native applications, and solutions running on constrained IoT hardware. Since each of these categories brings its own capabilities and constraints, the standards define multiple flows. These flows specify the sequence of messages between the client and the authorization server that ultimately results in token issuance.
Given the restrictions inherent to a browser environment, the implicit flow was introduced as a streamlined option for SPAs:

With the implicit flow, the SPA redirects the user to an authorization server where authentication occurs. The standards deliberately leave the authentication mechanism open—it could be a simple username/password prompt, various forms of two-factor authentication, Windows-based authentication for seamless single sign-on, or even delegation to another identity provider.
Upon successful authentication, the authorization server redirects the user back to the SPA. While this redirect pattern appears in several flows, what sets the implicit flow apart is that the authorization server places the issued tokens directly into the SPA's URL. The application extracts them from there and can then call the backend (resource server).
OIDC builds on this by adding an Identity Token (ID Token), which carries claims—key/value pairs—describing the authenticated user. Additionally, the UserInfo endpoint, a REST service defined by OIDC, offers supplementary user details.
The Challenge of Browser-Based Tokens: Is the Code Flow the Answer?
The implicit flow is not without its downsides. The most significant criticism—voiced prominently in current best practice recommendations—concerns the transmission of tokens via URL parameters. These parameters end up in browser history, server logs on the authorization server, and potentially in proxy logs. This creates multiple attack vectors for token theft.
These risks were known from the outset. As a result, common countermeasures involved manipulating the browser history with JavaScript and carefully configuring log settings. Similar workarounds addressed other known weaknesses of the implicit flow.
That said, using the implicit flow does not automatically make an application insecure. Yet building adequate defenses requires numerous mechanisms, and since security is only as strong as the weakest link, the best practice documents outright discourage its use in favor of better alternatives.
The recommended approach is the Authorization Code Flow, which arguably reflects the original design intent of OAuth 2 most closely:

In this flow, the authorization server returns a single-use code instead of tokens. The SPA then exchanges the code for the actual tokens over a secure HTTPS channel. To prevent interception and replay of that code, best practice documents mandate the use of PKCE (Proof Key for Code Exchange). This mechanism guarantees that only the client that initiated the flow can redeem the authorization code.
A Further Complication: Refreshing Tokens in the Browser
Beyond the issues addressed by adopting the Authorization Code Flow with PKCE, a deeper complication persists: browsers themselves lack a secure storage medium for tokens. XSS attacks and other injection vectors remain a persistent threat to SPAs—the OWASP Top 10 of 2021 ranks injection attacks, including cross-site scripting, in third place.
Industry best practice has therefore long favored short-lived access tokens, often with lifespans of roughly 10 minutes. This limits the blast radius if an attacker manages to extract a token.
However, short-lived tokens necessitate periodic renewal without user interaction. Users certainly don't want to re-enter their password every 10 minutes. Unfortunately, no truly elegant solution exists.
One frequently deployed technique is the so-called silent refresh, executed inside a hidden iframe:

Here, a cookie on the authorization server keeps track of the authenticated user, allowing the flow to proceed without prompting for credentials. Because this cookie is marked HTTP-only, it remains inaccessible to JavaScript-based attacks.
Within the hidden iframe, another implicit or code flow runs, so the user never notices the redirection. Although this method aligns with the specification, it is ultimately a workaround that brings its own fragility due to iframe handling. Worse, the use of iframes rules out SameSite cookies—yet SameSite is a key defense against CSRF attacks.
Refresh Tokens in the Browser: Generally Not Allowed
Another route for token renewal involves refresh tokens:

Refresh tokens allow clients to fetch fresh access tokens, identity tokens, and even new refresh tokens. But the original specifications explicitly discourage this pattern in browser-based environments. The rationale: if an attacker obtains a refresh token, they can continuously acquire new access tokens, effectively impersonating the user over an extended period.
Modern best practice documents adopt a slightly more permissive stance, though they still stress the need for a risk assessment before deploying refresh tokens. Such an assessment should consider the probability of token theft—linked to XSS exposure—and the potential impact of misuse.
Furthermore, the guidance for browser-based OAuth 2 requires that refresh tokens either be bound to the user or rotated upon each use. User-binding typically demands client certificates, which are rarely feasible in a browser context. The alternative is rotation: exchanging a used refresh token for a new one each time.
Rotation alone is not sufficient. Refresh tokens must still have a maximum lifetime, and they should expire after a period of inactivity. If the same refresh token is used by two different clients, one may well be an attacker. In that scenario, the authorization server should reject both the current and any subsequently issued refresh tokens.
Delving Deeper into Angular Security
Further exploration of these and other advanced security subjects in the Angular ecosystem is available through our Angular Security Workshop, led by the international security expert Dr. Philippe De Ryck. The workshop is 100% online and interactive, combining lectures, demonstrations, quizzes, and hands-on exercises.

All Details: Angular Security Workshop
Final Thoughts
As this discussion underscores, the browser is not a safe environment for storing security tokens. Moreover, no fully satisfactory mechanism exists for refreshing tokens within Single Page Applications.
These concerns drive the OAuth 2.0 working group to recommend a server-side approach to OAuth 2.0 and token management. For a closer look at that solution, refer to the second installment of this article series.
