Token, Session, and Transaction Lifetimes
O2ID mints and stores several kinds of short-lived state during authentication and token issuance. Each has a lifetime — how long it's valid before it expires and can no longer be used:
| Store | Built-in default |
|---|---|
| Access tokens | 1 hour |
| Refresh tokens | 30 days |
| Authorization codes | 10 minutes |
| Sessions | 12 hours |
| Login transactions | 10 minutes |
| Consent transactions | 10 minutes |
These are an auth/policy concern, not a storage-driver one — they apply identically regardless of which storage driver is configured.
Reading or updating tenant settings requires a role with the
tenant:settings:read/tenant:settings:update scopes; per-application
overrides use the same applications:update scope as any other application
field — see Using o2idctl and Managing Roles.
Overriding a lifetime
Every lifetime above can be overridden at two levels:
- Per tenant — a default for every application in that tenant.
- Per application — takes precedence over the tenant's own setting, for one specific application.
Resolution order is application override → tenant override → built-in default: the first one that's actually set wins.
Setting a tenant default
o2idctl tenant-settings get
o2idctl tenant-settings update --access-token-lifetime 30m --session-lifetime 8h
This changes the default for every application in the current tenant that doesn't set its own override.
Setting a per-application override
The same lifetime flags are accepted by
applications create and applications update:
o2idctl applications create --name "My App" \
--callback-url https://myapp.example.com/callback \
--access-token-lifetime 5m --refresh-token-lifetime 720h
o2idctl applications update <id> --session-lifetime 2h
An application's own override always wins over the tenant default, for that application only — every other application in the tenant is unaffected.
Clearing an override
Pass 0 or inherit as the value to remove an override and fall back to
the next level up (the tenant's own setting, then the built-in default):
o2idctl applications update <id> --access-token-lifetime inherit
A real 0-second lifetime is meaningless, so 0 is safe to use as the "clear
this override" signal rather than a genuine value.
Available flags
| Flag | Affects |
|---|---|
--access-token-lifetime | Access tokens |
--refresh-token-lifetime | Refresh tokens |
--authorization-code-lifetime | Authorization codes |
--session-lifetime | Sessions |
--login-transaction-lifetime | Login transactions |
--consent-transaction-lifetime | Consent transactions |
Each accepts a Go-style duration string (30m, 2h, 720h), or 0/inherit
to clear.
Which application a session or login transaction "belongs to"
Access tokens, refresh tokens, authorization codes, and consent transactions are always issued for a specific, already-authenticated application, so their override is unambiguous.
Sessions and login transactions are a little different: a login transaction
is created by /oauth2/authorize as soon as client_id is seen in the
request, before the user has even authenticated, and a session created at
login time is picked up from whichever login transaction (if any) the user
arrived through. In both cases, if a client_id was present, its
application's override is used; otherwise (e.g. a user landing directly on
/login with no in-flight authorization request) only the tenant override
and built-in default apply.
API reference
Tenant settings can also be read and updated directly, e.g. from a script:
GET /tenant/settings
PATCH /tenant/settings
PATCH accepts a partial lifetimes object; omitted fields are left
unchanged, and an explicit 0 clears that field's override. See the
API Reference for the full request/response shape, and
Managing Applications for the equivalent
per-application fields on /applications.