AuthSession
Overview
AuthSession represents one signed-in identity. It does not hold tokens directly: it's a pointer to the active AuthAccount inside linkedAccounts, which is where tokens actually live. See Sessions → for the full model explanation.
final session = await Authyra.instance.getSession();
print(session?.user.email);
print(session?.accessToken); // delegates to session.activeAccount
Fields
class AuthSession {
final AuthUser user;
final String activeAccountId;
final List<AuthAccount> linkedAccounts;
final SessionMetadata? metadata;
final DateTime createdAt;
final DateTime lastUsedAt;
}
| Field | Type | Description |
|---|---|---|
user | AuthUser | Identity profile: id, email, name, avatarUrl, metadata |
activeAccountId | String | AuthAccount.id currently in use |
linkedAccounts | List<AuthAccount> | Every provider-linked account for this user |
metadata | SessionMetadata? | Optional device/network context; never read internally |
createdAt | DateTime | When the session was first created |
lastUsedAt | DateTime | Most recent activity, drives recency sorting in AccountManager.getAll() |
AuthAccount
class AuthAccount {
final String id; // '${providerId}_${providerAccountId}' by default
final String userId;
final String providerId; // 'google', 'email', etc.
final String providerAccountId; // the provider's own id for this user
final String? accessToken;
final String? refreshToken;
final DateTime? tokenExpiresAt;
final Map<String, dynamic> providerData;
}
| Field | Description |
|---|---|
id | Unique id for this account entry, defaults to '${providerId}_${providerAccountId}' |
userId | The AuthUser.id this account belongs to |
providerId | The AuthProvider.id that authenticated this account |
providerAccountId | The provider's own identifier (Google sub, GitHub login, etc.) |
accessToken / refreshToken / tokenExpiresAt | Token data, optional |
providerData | Arbitrary provider-specific metadata (OAuth scopes, hosted domain, etc.) |
Computed getters
These all read from activeAccount (the entry in linkedAccounts matching activeAccountId) and return null/false when it can't be resolved:
String get providerId; // activeAccount?.providerId ?? ''
String? get accessToken;
String? get refreshToken;
DateTime? get expiresAt;
AuthAccount? get activeAccount;
isExpired
bool get isExpired
true when DateTime.now() is past expiresAt. false when expiresAt is null (no known expiry, e.g. cookie-session flows).
isExpiringSoon / shouldRefresh
bool isExpiringSoon([Duration threshold = const Duration(minutes: 5)])
bool shouldRefresh({Duration threshold = const Duration(minutes: 5)})
Semantically identical; shouldRefresh takes a named parameter and is what AuthyraClient's auto-refresh path uses internally with AuthConfig.refreshThreshold.
timeUntilExpiration
Duration get timeUntilExpiration
Remaining time until expiresAt. Returns Duration.zero when already expired or when expiresAt is null.
canRefresh
bool get canRefresh // refreshToken != null && refreshToken!.isNotEmpty
Multi-provider helpers
Set<String> get linkedProviderIds;
bool hasLinkedProvider(String providerId);
if (session.hasLinkedProvider('github')) {
showGitHubBadge();
}
linkedAccounts with more than one entry: GoogleProvider, GitHubProvider, etc. each derive AuthUser.id from their own subject claim, so signing in via two different providers registers as two separate accounts in SessionRegistry, not one linked identity. linkedAccounts is real, tested infrastructure; the linking flow itself isn't built yet.Mutation helpers
AuthSession is immutable. These return a new instance:
AuthSession markAsUsed(); // lastUsedAt = now
AuthSession refreshed({
required String newAccessToken,
String? newRefreshToken, // omit to keep the existing one
required DateTime newExpiresAt,
});
final renewed = session.refreshed(
newAccessToken: result.accessToken,
newExpiresAt: result.expiresAt,
);
Serialisation
Map<String, dynamic> toJson();
factory AuthSession.fromJson(Map<String, dynamic> json);
Persisted by SessionManager under a session:{userId} storage key. See Storage → for the key layout.