Identity sessions
reauth.identity_session
IdentitySession
dataclass
IdentitySession(
id: Any | None,
token_hash: TokenHash,
expires_at: int,
identity_id: Any,
amr: list[AuthenticationMethodReference],
context: dict[str, Any] | None = None,
refresh_token_hash: TokenHash | None = None,
refresh_token_expires_at: int | None = None,
family_id: Any | None = None,
replaced_by_id: Any | None = None,
revoked_at: int | None = None,
)
The authenticated state of an identity, accessed through a session token.
Attributes:
| Name | Type | Description |
|---|---|---|
id |
Any | None
|
The stored session ID, or None before insertion. |
token_hash |
TokenHash
|
The HMAC-SHA256 hash of the session token. |
expires_at |
int
|
The access token expiration as a Unix timestamp in seconds. |
identity_id |
Any
|
The ID of the authenticated identity. |
amr |
list[AuthenticationMethodReference]
|
The authentication methods used to authenticate the identity. |
context |
dict[str, Any] | None
|
Optional additional data stored with the session. |
refresh_token_hash |
TokenHash | None
|
The refresh token hash, or None if renewal is disabled. |
refresh_token_expires_at |
int | None
|
The family's absolute deadline, or None if this session has no refresh token. Replacements inherit the deadline. |
family_id |
Any | None
|
The initial session's ID, or None before initial insertion. |
replaced_by_id |
Any | None
|
The replacement session's ID, or None if not replaced. |
revoked_at |
int | None
|
The revocation timestamp, or None if not revoked. |
id
instance-attribute
id: Any | None
token_hash
instance-attribute
token_hash: TokenHash
expires_at
instance-attribute
expires_at: int
identity_id
instance-attribute
identity_id: Any
amr
instance-attribute
amr: list[AuthenticationMethodReference]
context
class-attribute
instance-attribute
context: dict[str, Any] | None = None
refresh_token_hash
class-attribute
instance-attribute
refresh_token_hash: TokenHash | None = None
refresh_token_expires_at
class-attribute
instance-attribute
refresh_token_expires_at: int | None = None
family_id
class-attribute
instance-attribute
family_id: Any | None = None
replaced_by_id
class-attribute
instance-attribute
replaced_by_id: Any | None = None
revoked_at
class-attribute
instance-attribute
revoked_at: int | None = None
is_expired
is_expired() -> bool
Check if the access token has expired.
Returns:
| Type | Description |
|---|---|
bool
|
True if the current time is at or past expiration, False otherwise. |
IdentitySessionException
IdentitySessionException(message: str | None = None)
InvalidSessionTokenException
InvalidSessionTokenException(message: str | None = None)
Bases: IdentitySessionException
Raised when an access token is unknown, malformed, revoked, or replaced.
ExpiredSessionException
ExpiredSessionException(message: str | None = None)
InvalidRefreshTokenException
InvalidRefreshTokenException(message: str | None = None)
Bases: IdentitySessionException
Raised when a refresh token is unknown, malformed, disabled, or revoked.
ExpiredRefreshTokenException
ExpiredRefreshTokenException(message: str | None = None)
ReusedRefreshTokenException
ReusedRefreshTokenException(message: str | None = None)
Bases: IdentitySessionException
Raised after revoking a family because a consumed refresh token was reused.
IdentitySessionService
IdentitySessionService(
*,
hash_secret: str,
token_prefix: str = "reauth_is_",
lifetime: timedelta = datetime.timedelta(hours=24),
refresh_token_prefix: str = "reauth_isr_",
refresh_token_lifetime: timedelta = datetime.timedelta(
days=30
),
)
Bases: ABC
Abstract base class for managing identity sessions and optional refresh tokens.
Implementers provide token lookups, initial insertion, atomic replacement, and family revocation. Retain replaced sessions until the family's absolute deadline so their hashes can identify refresh token reuse.
Initialize the identity session service.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
hash_secret
|
str
|
The ASCII secret used to compute token hashes. |
required |
token_prefix
|
str
|
The session token prefix. Defaults to "reauth_is_". |
'reauth_is_'
|
lifetime
|
timedelta
|
The access token lifetime. Defaults to 24 hours. |
timedelta(hours=24)
|
refresh_token_prefix
|
str
|
The refresh token prefix. Defaults to "reauth_isr_". |
'reauth_isr_'
|
refresh_token_lifetime
|
timedelta
|
The absolute lifetime of a refreshable family, measured from initial issuance. Defaults to 30 days. |
timedelta(days=30)
|
hash_secret
instance-attribute
hash_secret = hash_secret
token_prefix
instance-attribute
token_prefix = token_prefix
lifetime
instance-attribute
lifetime = lifetime
refresh_token_prefix
instance-attribute
refresh_token_prefix = refresh_token_prefix
refresh_token_lifetime
instance-attribute
refresh_token_lifetime = refresh_token_lifetime
issue
async
issue(
identity_id: Any,
*,
amr: list[AuthenticationMethodReference],
refresh_token: bool = False,
**context: Any,
) -> tuple[str, str | None, IdentitySession]
Issue and persist a session for an authenticated identity.
The caller is responsible for authenticating the identity before issuance. Only token hashes are persisted; plaintext tokens are returned to the caller.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
identity_id
|
Any
|
The ID of the authenticated identity. |
required |
amr
|
list[AuthenticationMethodReference]
|
The authentication methods used to authenticate the identity. |
required |
refresh_token
|
bool
|
Whether to issue a refresh token. Defaults to False. |
False
|
**context
|
Any
|
Optional additional data to store with the session. |
{}
|
Returns:
| Type | Description |
|---|---|
str
|
A tuple of (token, refresh_token, IdentitySession instance). The |
str | None
|
refresh token is None when renewal is disabled. |
validate
async
validate(token: str) -> IdentitySession
Validate an access token and return its identity session.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
token
|
str
|
The access token to validate. |
required |
Returns:
| Type | Description |
|---|---|
IdentitySession
|
The corresponding IdentitySession instance. |
Raises:
| Type | Description |
|---|---|
InvalidSessionTokenException
|
If the token is malformed, unknown, revoked, or belongs to a replaced session. |
ExpiredSessionException
|
If the access token has expired. |
refresh
async
refresh(
token: str, *, refresh_token: bool = True
) -> tuple[str, str | None, IdentitySession]
Consume a refresh token and atomically replace its session.
Both previous tokens become invalid. The replacement retains the identity, AMR, context, family, and absolute deadline, even if access has expired. Reuse of a consumed refresh token revokes its whole family.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
token
|
str
|
The refresh token to consume. |
required |
refresh_token
|
bool
|
Whether to issue another refresh token. Defaults to True. False issues a final session whose expiry is still capped by the family's deadline, with no further renewal capability. |
True
|
Returns:
| Type | Description |
|---|---|
str
|
A tuple of (token, refresh_token, IdentitySession instance). The |
str | None
|
refresh token is None when renewal is disabled. |
Raises:
| Type | Description |
|---|---|
InvalidRefreshTokenException
|
If the token is malformed, unknown, revoked, or otherwise no longer refreshable. |
ExpiredRefreshTokenException
|
If the absolute deadline has passed. |
ReusedRefreshTokenException
|
If the token was already consumed. Family revocation is persisted before this exception is raised. |
revoke
async
revoke(token: str) -> None
Revoke an entire family identified by an access or refresh token.
Expired and replaced tokens can still identify a family. Unknown, malformed, and already-revoked tokens succeed without error.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
token
|
str
|
An access token or refresh token from the family to revoke. |
required |
insert
abstractmethod
async
insert(identity_session: IdentitySession) -> typing.Any
Atomically insert a session and initialize its family ID.
If family_id is None, set the stored family_id to the generated record ID in the same transaction. Preserve an explicitly supplied family ID.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
identity_session
|
IdentitySession
|
The complete session model to insert. |
required |
Returns:
| Type | Description |
|---|---|
Any
|
The ID of the inserted session. |
get_by_token_hash
abstractmethod
async
get_by_token_hash(
token_hash: TokenHash,
) -> IdentitySession | None
Retrieve a session by its access token hash, regardless of its validity.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
token_hash
|
TokenHash
|
The access token hash to look up. |
required |
Returns:
| Type | Description |
|---|---|
IdentitySession | None
|
The stored session, including expired, replaced, or revoked rows, |
IdentitySession | None
|
or None if not found. |
get_by_refresh_token_hash
abstractmethod
async
get_by_refresh_token_hash(
refresh_token_hash: TokenHash,
) -> IdentitySession | None
Retrieve a session by its refresh token hash, regardless of its validity.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
refresh_token_hash
|
TokenHash
|
The refresh token hash to look up. |
required |
Returns:
| Type | Description |
|---|---|
IdentitySession | None
|
The stored session, including expired, replaced, or revoked rows, |
IdentitySession | None
|
or None if not found. |
replace
abstractmethod
async
replace(
previous_session: IdentitySession,
new_session: IdentitySession,
) -> typing.Any | None
Atomically replace a session if its refresh token is still usable.
Serialize with all replacements and revocations in the same family, for example by locking the retained initial session row. Reload the previous session under that lock: its refresh hash must still match, its refresh deadline must be in the future, and it must be neither revoked nor replaced. Also reject a revoked or missing family root.
Insert new_session with the same family ID and set the previous row's replaced_by_id to the new ID. Commit both changes before returning; roll back both on failure. Do not call the public issue() method.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
previous_session
|
IdentitySession
|
The previously retrieved session to replace. |
required |
new_session
|
IdentitySession
|
The complete replacement model to persist. |
required |
Returns:
| Type | Description |
|---|---|
Any | None
|
The replacement ID, or None with no changes if the previous session |
Any | None
|
is no longer eligible. Propagate storage failures after rollback. |
revoke_family
abstractmethod
async
revoke_family(identity_session: IdentitySession) -> None
Persist revocation of every session in the supplied session's family.
Use identity_session.revoked_at, set by the service, for rows not yet revoked. Preserve earlier revocation timestamps, hashes, and lineage. Serialize with replace() through the same family lock and commit before returning. A caller's subsequent exception must not undo revocation. Missing or already-revoked families succeed without error.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
identity_session
|
IdentitySession
|
The session identifying the family and revocation time. |
required |