Sigra.JWT.RefreshToken (Sigra v1.20.0)

Copy Markdown View Source

Refresh token management with family-based reuse detection.

Refresh tokens are opaque, hashed tokens stored in the user_tokens table with context: "api_refresh". Each token belongs to a "family" identified by a UUID. When a refresh token is rotated, the old token is marked as superseded and a new token is created in the same family.

Reuse Detection (Auth0 Pattern)

If a superseded token is presented for rotation, the entire token family is revoked. This detects stolen refresh tokens: if an attacker uses a stolen token after the legitimate user has already rotated it, the reuse triggers family-wide revocation, protecting both parties.

Storage

Token metadata (family_id, scopes, superseded_at) is stored as JSON in the sent_to field of the user_tokens table.

Summary

Functions

Creates a new refresh token for the given user.

Revokes a specific refresh token by marking it as superseded.

Revokes all refresh tokens for a user.

Revokes all tokens in a family by marking them as superseded.

Rotates a refresh token: supersedes the old token and creates a new one in the same family.

Functions

create(config, user, scopes, opts \\ [])

@spec create(Sigra.Config.t(), struct(), [String.t()], keyword()) ::
  {String.t(), struct()}

Creates a new refresh token for the given user.

Returns {raw_token, token_record} where raw_token is the opaque string to send to the client.

Options

  • :user_token_schema - Required. The Ecto schema module for user tokens.

revoke(config, raw_token, opts \\ [])

@spec revoke(Sigra.Config.t(), String.t(), keyword()) ::
  :ok | {:error, :invalid_token}

Revokes a specific refresh token by marking it as superseded.

Options

  • :user_token_schema - Required. The Ecto schema module for user tokens.

revoke_all_for_user(config, user_id, opts \\ [])

@spec revoke_all_for_user(Sigra.Config.t(), term(), keyword()) ::
  {:ok, non_neg_integer()}

Revokes all refresh tokens for a user.

Used when a password is changed to invalidate all existing refresh tokens.

Options

  • :user_token_schema - Required. The Ecto schema module for user tokens.

revoke_family(config, family_id, opts \\ [])

@spec revoke_family(Sigra.Config.t(), String.t(), keyword()) ::
  {:ok, non_neg_integer()}

Revokes all tokens in a family by marking them as superseded.

Options

  • :user_token_schema - Required. The Ecto schema module for user tokens.

rotate(config, raw_token, opts \\ [])

@spec rotate(Sigra.Config.t(), String.t(), keyword()) ::
  {:ok, String.t(), struct(), [String.t()]}
  | {:error, :invalid_token | :token_expired | :reuse_detected}

Rotates a refresh token: supersedes the old token and creates a new one in the same family.

Returns {:ok, raw_new_token, new_record, scopes} on success.

Reuse Detection

If the presented token has already been superseded (i.e., it was already rotated), this indicates token theft. The entire family is revoked and {:error, :reuse_detected} is returned.

Options

  • :user_token_schema - Required. The Ecto schema module for user tokens.