Sessions
AuthSession is the core data object that represents an authenticated user's active session. It carries the user's identity, tokens, expiry metadata, and the provider that created it.
Fields
class AuthSession {
final String providerId; // 'google', 'email', etc.
final AuthUser user;
final String? accessToken;
final String? refreshToken;
final DateTime? expiresAt;
final List<String> linkedProviders;
final DateTime createdAt;
final DateTime lastUsedAt;
}
| Field | Description |
|---|---|
providerId | Slug of the provider that created this session |
user | Identity profile — id, email, name, avatarUrl, metadata |
accessToken | Short-lived token for API requests. null for cookie-session flows |
refreshToken | Long-lived token for silent renewal. null if not returned by the provider |
expiresAt | UTC expiry of accessToken. null = no known expiry |
linkedProviders | All providers linked to this account (for multi-provider users) |
createdAt | When this session was first created |
lastUsedAt | Timestamp of the most recent activity — used for recency sorting |
Lifecycle
signIn()
└─ provider.signIn() returns AuthSignInResult
└─ AuthyraClient builds AuthSession
└─ SessionManager.saveSession(session)
└─ persisted to AuthStorage
└─ authStateChanges emits AuthState.authenticated
↓ (token approaching expiry)
session.shouldRefresh → true
└─ provider.refreshToken(session.refreshToken)
└─ session.refreshed(newAccessToken, newExpiresAt)
└─ SessionManager.updateSession()
└─ authStateChanges emits refreshed state
↓ (sign-out)
signOut()
└─ provider.signOut() [if supportsSignOut]
└─ SessionManager.clearActiveSession()
└─ storage cleared
└─ authStateChanges emits AuthState.unauthenticated
Expiry helpers
isExpired
bool get isExpired
true when DateTime.now() is past expiresAt. Returns false when expiresAt is null.
isExpiringSoon
bool isExpiringSoon([Duration threshold = const Duration(minutes: 5)])
true when the token expires within threshold. Use for manual pre-emptive refresh:
final session = await Authyra.instance.getSession();
if (session?.isExpiringSoon(const Duration(minutes: 10)) ?? false) {
await Authyra.instance.refreshSession();
}
shouldRefresh
bool shouldRefresh({Duration threshold = const Duration(minutes: 5)})
Semantically identical to isExpiringSoon but accepts a named parameter — used internally by AuthyraClient's auto-refresh scheduler:
if (session.shouldRefresh(threshold: config.refreshThreshold)) {
await client.refresh(session);
}
timeUntilExpiration
Duration get timeUntilExpiration
Remaining time until the access token expires. Returns Duration.zero when already expired or when expiresAt is null.
final remaining = session?.timeUntilExpiration ?? Duration.zero;
print('Token valid for ${remaining.inMinutes} more minutes');
Token refresh
When the session should be refreshed:
AuthyraClientcallsprovider.refreshToken(session.refreshToken).- The provider returns an
AuthTokenResult. - The session is updated via
session.refreshed(...). - The new session is persisted and
authStateChangesemits the updated state.
// The refreshed() helper produces an updated AuthSession:
final renewed = session.refreshed(
newAccessToken: result.accessToken,
newRefreshToken: result.refreshToken, // null = keep existing
newExpiresAt: result.expiresAt,
);
When refreshToken returns null (expired or revoked), the session is cleared and AuthState.unauthenticated() is emitted.
canRefresh
bool get canRefresh // refreshToken != null && refreshToken.isNotEmpty
Quick check before attempting a refresh. Providers that don't return a refresh token (e.g., cookie-session flows) will have canRefresh: false.
Reading the session
// Async — full session object
final session = await Authyra.instance.getSession();
print('Provider: ${session?.providerId}');
print('Expires: ${session?.expiresAt}');
print('Can refresh: ${session?.canRefresh}');
// Async — just the access token (triggers auto-refresh if needed)
final token = await Authyra.instance.getAccessToken();
myHttpClient.options.headers['Authorization'] = 'Bearer $token';
Serialisation
AuthSession is serialised to/from JSON for persistence in AuthStorage. Timestamps are encoded as ISO 8601 strings:
{
"providerId": "google",
"user": { "id": "123", "email": "alice@example.com" },
"accessToken": "ya29.xxx",
"refreshToken": "1//yyy",
"expiresAt": "2026-03-01T12:00:00.000Z",
"linkedProviders": ["google"],
"createdAt": "2026-02-01T08:00:00.000Z",
"lastUsedAt": "2026-02-23T10:30:00.000Z"
}
SecureAuthStorage in Flutter, or your own encrypted implementation for other runtimes.Multi-account sessions
SessionRegistry maintains an in-memory map of active sessions keyed by user.id. AccountManager exposes the public API:
final accounts = Authyra.instance.accounts;
// All signed-in accounts, sorted by last activity
final users = await accounts.getAll();
// Activate a different account
await accounts.switchTo(userId);
// Sign out one account, keep others active
await accounts.signOut(userId);
// Sign out all accounts
await accounts.signOutAll();
// Remove expired sessions
await accounts.cleanExpired();
The active account limit is controlled by AuthConfig.maxAccounts (default: 5).
linkedProviders
When a user signs in with multiple providers, all provider IDs are stored in linkedProviders. Use this to render a "connected accounts" UI:
final session = await Authyra.instance.getSession();
final providers = session?.linkedProviders ?? [];
if (session?.hasLinkedProvider('github') ?? false) {
showGitHubBadge();
}
See also
- Reactivity → —
authStateChangesand synchronous state cache - Storage → — how sessions are persisted
- Token Refresh guide →
- Multi-Account guide →