Skip to content

Issued access tokens are theoretically forever valid #3270

@imCorfitz

Description

@imCorfitz

Link to reproduction

N/A

To Reproduce

Setup a new Payload CMS and sign in using API.

Describe the Bug

TL;DR

Main concern is that an access token is forever functional and can forever be renewed - and can't be revoked.

Current refresh token flow

When an issued access_token is about to expire, one can call the [user-collection]/refresh-token endpoint to retrieve a new token.

Quoted from current documentation:

If your user has a token that is about to expire, but the user is still active and using the app, you might want to use the refresh operation to receive a new token by sending the operation the token that is about to expire.

This operation requires a non-expired token to send back a new one. If the user's token has already expired, you will need to allow them to log in again to retrieve a new token.

If successful, this operation will automatically renew the user's HTTP-only cookie and will send back the updated token in JSON.

This implies that if anyone were to gain access to an access token as a string, they would in theory forever be able to renew the token and there would be no way as admin or user to invalidate or detect this. This could prove critical especially if said access token should belong to an admin.

The OAuth approach

Access Tokens

Access tokens are issued as short-living "tickets" allowing the carrier of said token to access and act on behalf of the subject to which said token has been issued.

Refresh Tokens

Refresh tokens can be either JWTs, opaque strings, or strings of encrypted data which represents an active session. When an access token has expired, the refresh token is used to request a new access token. The refresh token acts as the receipt of a transaction and proves that for a set amount of time, the subject can request access to a resource or service.

Refresh tokens are either stored in a Database on the authentication service which issues tokens, or preferably are self-contained and contain certain data that associates the subject with an active session id and expiration time. The refresh token can also contain data of the audience, which can be a specific application or resource, which helps to set privileges specific for the issued access tokens.

Whenever a refresh token is used to request a new access token, the refresh token is first unwrapped/verified on the auth service. Then the session_id contained in the refresh token is verified by ensuring it hasn't been previously revoked. Hereafter, the subject_id contained in the refresh token is used to issue a new access token.

To revoke a refresh token, oftentimes the session_id is added to a database (RedisDB is usually a good choice) and automatically set to expire from the db table when the refresh token itself is set to expire. This reduces the number of entries in a db necessary, and handles garbage collection automatically.

Client ID and Key

An added level of security would be to issue client credentials which are generated per resource and application, and often tied to the audience identifier in the refresh token.

This way, whenever a refresh token is used to request a new access token, the application/resource is also required to send along their secure client credentials to ensure the action is indeed done by the correct audience and not using a potentially leaked refresh token.

Revoke token

Access tokens can't per definition not be revoked. Hence why they should be short-lived. When a user sends a logout request, the session_id (which could be present in both access token and refresh token) is added to the db table for revoked tokens. Next time a refresh token is used to request and access token, this request is then denied as the session_id is revoked.

From within admin, it could likewise be possible to create a session table for users, which simply lists the session_ids, the create date and expiration of each issued refresh token, and allow the user to revoke manually from within admin. This table is only used to store records or currently active sessions and is only to facilitate the process of revoking a token for the user.

Payload Version

1.15.2

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions