Access token refresh security model (non-PKCE)

Can someone help me understand the justification of the security model for refreshing access tokens (non-PKCE)?

  • To authorize, a client ID and secret must be provided
    • Ok, that makes perfect sense
  • Authorize yields a refresh token and an access token
    • I suppose the added security of the refresh token is just that it’s used less often than access token. Kind of weak, but fine, ok
  • To refresh the access token, the client ID and secret are needed (and refresh and access tokens, too)
    • This introduces a security issue on the client side:

The refresh, for most cases, will very likely be done automatically. This means the automation code (e.g. cron job) needs access to the client ID and the secret. This means the client ID and secret must be stored in a cryptographically secured way on the client system, where they otherwise wouldn’t need to be.

This isn’t the case for the initial authorization, since that will likely not be done automatically (because the need for actually, manual authorization from the Square site.)

Furthermore, it raises the question: what’s the point of the refresh token? It can always be obtained with only the client ID and secret, and it’s only useful when used in conjunction with the client ID and secret. It would seem to me, therefore, it adds no additional security. It’s completely superfluous.

Indeed, any information it could possibly refer to, could just be referred to by the access token.

My suggestions: remove the need for the client ID and secret when refreshing tokens. The riskiness of the need to securely store the client ID and secret on virtually every client system far out weighs any perceived added security. The refresh token, one would imagine, is the proxy for the the client ID and secret when refreshing (just as the access token is the proxy when doing everything except refreshing.)

Or explain to me what I’m missing? Sincerely.

The current model with both client credentials and refresh tokens serves multiple security purposes:

  1. Credential Separation

    • Client credentials (ID & secret) prove the application’s identity
    • Refresh tokens prove user authorization
    • Access tokens provide temporary access rights
  2. Security Benefits

    • If a refresh token is compromised, the attacker still needs valid client credentials
    • If client credentials are compromised, the attacker still needs valid refresh tokens
    • This “defense in depth” approach requires compromising multiple credentials
  3. Token Revocation

    • Square can revoke all refresh tokens for a compromised application
    • Individual refresh tokens can be revoked without affecting the application
    • Access tokens have short lifespans to limit exposure

Client Credential Storage
You raise a valid point about secure credential storage. Here are some recommended approaches:

  1. Use environment variables or secure credential managers
  2. Keep credentials on backend servers, not client devices
  3. Use infrastructure security tools (AWS Secrets Manager, HashiCorp Vault, etc.)

Refresh Token Purpose
Refresh tokens serve several important purposes:

  1. They represent specific user authorization
  2. They can be revoked individually
  3. They allow for user-specific access control
  4. They enable token rotation for security

Here’s a recommended architecture:

  1. Backend Service

    • Stores client credentials securely
    • Handles token refresh
    • Provides access tokens to clients
  2. Client Applications

    • Never store client credentials
    • Only handle access tokens
    • Request new tokens from backend
  3. Token Management

    • Implement proactive token refresh
    • Handle token rotation
    • Monitor token usage

Alternative Approaches

While removing client credentials from refresh flows might seem simpler, it would reduce security by:

  1. Eliminating application identity verification
  2. Making it harder to detect compromised tokens
  3. Reducing ability to manage application access :slight_smile:

If the client credentials have to be passed along every time the refresh token is used, and vice versa, then every risk occasion to leak client credentials is identical to every risk occasion to leak the refresh token. At least if client credentials are not passed so frequently, then there are less risk occasions for them to be leaked.

Furthermore, if the refresh token can always be obtained using the client credentials, then if the client credentials are compromised, any perceived security benefit of the refresh token is nullified. The refresh token doesn’t add any additional security.

What’s the use case for revoking a refresh token without revoking the access token? (That seems like it would be very confusing, and very possibly a security risk via user error.) Since the unexpired access token is needed to refresh itself, wouldn’t it be sufficient to just revoke the access token?

It would be infinitely more secure to not store them at all.

Since access tokens are always derived from refresh tokens, access tokens can accomplish this.

Again, this applies to access tokens as well. No need for the refresh token.

Again, since access tokens are always derived from refresh tokens, the access tokens already have this property. No need for the refresh token.

Since the access tokens expire, the rotation can come just from the access tokens. No need for the refresh token.

All of these steps can be accomplished without any loss of security, if the token refresh step just omits the refresh token.

Since the refresh token is essentially redundant to the functionality and usage of what could just be in the access token, the added security is analogous to having a basic login credentials scheme requiring two passwords instead of one (not 2FA, just two passwords), marginally more secure at best. One might as well just have a longer password.

However, requiring automated systems to take on an additional burden of securing highest-privileged credentials is a significant security model shortcoming.

In summary, even If one were somehow convinced that there was an absolute benefit to requiring client credentials and tokens for every refresh, the redundancy of the refresh token wrt the access token remains.