---
title: "Configuration — Refresh Tokens for Laravel | Roundly"
description: "Every config key, default and env variable — table, key type, lifetimes, token length, hashing, rotation grace and pruning."
url: https://roundly-consulting.com/open-source/docs/refresh-tokens-for-laravel/configuration
language: en
---

[All packages](https://roundly-consulting.com/open-source.md)

[Refresh Tokens for Laravel](https://roundly-consulting.com/open-source/docs/refresh-tokens-for-laravel.md)

# Configuration

The package works with zero configuration — every key has a sensible env-backed default. The published config/refresh-tokens.php:

```php
use RoundlyConsulting\RefreshTokens\Enums\DeviceType;
use RoundlyConsulting\RefreshTokens\Models\RefreshToken;

return [
    // Storage
    'table' => env('REFRESH_TOKENS_TABLE', 'refresh_tokens'),
    'model' => RefreshToken::class,
    'device_type_cast' => DeviceType::class,
    'key_type' => env('REFRESH_TOKENS_KEY_TYPE', 'bigint'),

    // Token lifetime & shape
    'ttl' => env('REFRESH_TOKENS_TTL', 2_592_000),                   // seconds; 30 days (sliding)
    'absolute_ttl' => env('REFRESH_TOKENS_ABSOLUTE_TTL', 7_776_000), // seconds; 90 days
    'token_length' => env('REFRESH_TOKENS_LENGTH', 64),              // min 32, max 4096

    // Hashing at rest
    'hash' => [
        'algo' => env('REFRESH_TOKENS_HASH_ALGO', 'sha256'),
        'key' => env('REFRESH_TOKENS_HASH_KEY'), // optional HMAC pepper; null = plain hash
    ],

    // Rotation / anti-replay
    'rotation' => [
        'grace' => env('REFRESH_TOKENS_ROTATION_GRACE', 0),
    ],

    // Expiry sweeping (the host schedules the command / model:prune)
    'prune' => [
        'after' => env('REFRESH_TOKENS_PRUNE_AFTER', 30), // days past revoke/expiry; at least 1
    ],
];
```

## Every key

| Key | Default | Env | Purpose |
| --- | --- | --- | --- |
| `table` | refresh\_tokens | `REFRESH_TOKENS_TABLE` | Table name. A blank value is not set, so refresh\_tokens applies; a non-string value throws. |
| `model` | RefreshToken::class | — | Token model; swap for a subclass of the package model. Anything that is not RefreshToken or a subclass throws. |
| `device_type_cast` | DeviceType::class | — | Eloquent cast for device\_type — the DeviceType enum by default; set 'string' (or any Eloquent cast) to store a free-form device name verbatim. A blank value is not set, so the DeviceType enum applies; a non-string value throws. |
| `key_type` | bigint | `REFRESH_TOKENS_KEY_TYPE` | Primary-key type shared by every owner model: bigint, uuid or ulid (blank is not set, so bigint applies). Any other value throws InvalidConfigurationException. |
| `ttl` | 2592000 (30 days) | `REFRESH_TOKENS_TTL` | Default sliding lifetime per issue/rotation, in seconds. At least 1. |
| `absolute_ttl` | 7776000 (90 days) | `REFRESH_TOKENS_ABSOLUTE_TTL` | Default absolute cap on a session, stored when the family is rooted. 0 disables; a negative value throws. |
| `token_length` | 64 | `REFRESH_TOKENS_LENGTH` | Plaintext length in base64url chars (~384 bits at 64). 32–4096, otherwise it throws. |
| `hash.algo` | sha256 | `REFRESH_TOKENS_HASH_ALGO` | At-rest digest; allowlisted to sha256, sha384 and sha512 (blank is not set, so sha256 applies; anything else throws). |
| `hash.key` | null | `REFRESH_TOKENS_HASH_KEY` | Optional HMAC pepper; not set (null or blank) = plain hash, a non-string throws. |
| `rotation.grace` | 0 | `REFRESH_TOKENS_ROTATION_GRACE` | Seconds a re-presented token stays benign before it counts as reuse. 0 = strict; negative throws. |
| `prune.after` | 30 | `REFRESH_TOKENS_PRUNE_AFTER` | Days to retain rows past revoke/expiry before pruning. At least 1 day; below that throws. |

## Environment

Every key except model and device\_type\_cast reads from env, so you rarely publish the config at all:

```bash
REFRESH_TOKENS_TABLE=refresh_tokens
REFRESH_TOKENS_KEY_TYPE=bigint
REFRESH_TOKENS_TTL=2592000
REFRESH_TOKENS_ABSOLUTE_TTL=7776000
REFRESH_TOKENS_LENGTH=64
REFRESH_TOKENS_HASH_ALGO=sha256
REFRESH_TOKENS_HASH_KEY=
REFRESH_TOKENS_ROTATION_GRACE=0
REFRESH_TOKENS_PRUNE_AFTER=30
```

## Validated configuration

Every key fails loud instead of being silently coerced, so an env typo can’t degrade the token store:

- hash.algo is restricted to the SHA-2 allowlist (sha256, sha384, sha512). A blank value is not set, so sha256 applies; anything else — md5, crc32b, … — throws InvalidTokenConfigurationException.
- token\_length must be between 32 and 4096 characters; outside that range it throws instead of minting a brute-forceable token.
- Every integer — ttl, absolute\_ttl, token\_length, rotation.grace and prune.after — is read strictly: an int or a canonical integer string ('30', as env values arrive). A key that is not set — absent, null or blank ('', what KEY= in .env gives) — takes its default; 'five', '1.5' or a value out of range throws InvalidTokenConfigurationException naming the key — never a silent 0 or default.
- table and device\_type\_cast must be strings; a blank one is not set, so its default applies. hash.key may be null or blank (no pepper), but a value that is not a string at all throws rather than silently dropping the pepper.
- key\_type accepts bigint, uuid or ulid; anything else throws InvalidConfigurationException naming the key and the value. A typo such as guid would otherwise build a bigint owner\_id for uuid or ulid owners, and nothing would fail until rows stopped joining. id, the package’s spelling before it adopted the shared key type, is no longer accepted — use bigint.
- model must be RefreshToken or a subclass of it; anything else throws InvalidConfigurationException naming the key instead of silently falling back to the packaged model.

## Device-type cast

device\_type is cast to the packaged DeviceType enum (desktop, mobile, tablet, bot, unknown) by default. If your user-agent parser emits a richer, free-form vocabulary, store it verbatim with any Eloquent cast string:

```php
// config/refresh-tokens.php — store a free-form device vocabulary verbatim
'device_type_cast' => 'string',
```

## Inspecting the live configuration

```bash
php artisan about --only=refresh-tokens
```

The about section is secret-safe — nothing a support screenshot could leak:

- Token model, Owner (the morph key type), Sliding TTL, Absolute TTL (or DISABLED), Token length, Hash algorithm, Rotation grace (or STRICT) and Prune after. Sliding TTL, Absolute TTL, Token length, Hash algorithm, Rotation grace and Prune after read INVALID when the value is malformed — about reports it instead of throwing.
- Table reports DEFAULT or CUSTOM, never the name.
- Hash pepper reports SET or MISSING, never the value.
- Access-token revoker reports NONE (no-op) or BOUND.

## Show your open-source love

This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.

[More ways to support, including crypto](https://roundly-consulting.com/support-us.md)

By donating, you agree to our [donation terms](https://roundly-consulting.com/donation-terms.md).

[Support our open source work (opens in a new tab)](https://donate.stripe.com/dRmeVe8FX5PF1Qd9pXcEw00) [Join us on Patreon (opens in a new tab)](https://www.patreon.com/cw/roundly)

## Want this built into your product?

We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.

[Get a quote in 48 hours](https://roundly-consulting.com/contact.md) [Browse all packages](https://roundly-consulting.com/open-source/docs/refresh-tokens-for-laravel.md)
