Sessions in Ory Kratos represent authenticated user contexts. They track who is logged in, when they authenticated, and what authentication methods were used.
Session structure
A session contains comprehensive information about an authenticated user:
type Session struct {
ID uuid . UUID
Active bool
ExpiresAt time . Time
AuthenticatedAt time . Time
AuthenticatorAssuranceLevel identity . AuthenticatorAssuranceLevel
AMR AuthenticationMethods
IssuedAt time . Time
Identity * identity . Identity
Devices [] Device
}
Session fields
ID : Unique session identifier (UUID)
Active : Whether the session is currently active
ExpiresAt : When the session expires
IssuedAt : When the session was created
AuthenticatedAt : When the user last authenticated (updated for MFA)
AuthenticatorAssuranceLevel : The AAL achieved (aal0, aal1, aal2)
AMR : Authentication Methods References - list of methods used
Identity : The authenticated identity (may be null for partial sessions)
Token : Session token for API authentication
LogoutToken : Token used to revoke the session
Tokenized : JWT representation (when using session-to-JWT feature)
Devices : History of devices/locations where session was used
Includes IP address, user agent, and geolocation
Session tokens
Kratos uses opaque session tokens for authentication.
Session tokens have the format:
Example:
ory_st_MP2YWEMeM8MxjkGKpH4dqOQ4Q4DlSPaj
Token storage
Tokens are stored:
Browser: HTTP-only cookie
For browser clients, tokens are stored in secure, HTTP-only cookies: Set-Cookie: ory_kratos_session=ory_st_...; Path=/; HttpOnly; Secure; SameSite=Lax
Native/API: Bearer token
For native apps and API clients, tokens are returned in the response and sent via header: Authorization : Bearer ory_st_MP2YWEMeM8MxjkGKpH4dqOQ4Q4DlSPaj
Or custom header: X-Session-Token : ory_st_MP2YWEMeM8MxjkGKpH4dqOQ4Q4DlSPaj
Token validation
Kratos validates tokens by:
Looking up the token in the database
Checking if the session is active
Verifying the session hasn’t expired
Confirming the identity is active
func ( s * Session ) IsActive () bool {
return s . Active &&
s . ExpiresAt . After ( time . Now ()) &&
( s . Identity == nil || s . Identity . IsActive ())
}
Authenticator Assurance Level (AAL)
AAL indicates the strength of authentication:
Level Description Examples AAL0 No authentication Initial state AAL1 Single-factor authentication Password, Social sign-in, Passkey AAL2 Multi-factor authentication Password + TOTP, Password + WebAuthn
AAL calculation
AAL is determined by the authentication methods used:
func ( s * Session ) SetAuthenticatorAssuranceLevel () {
var isAAL1 , isAAL2 bool
for _ , amr := range s . AMR {
switch amr . AAL {
case identity . AuthenticatorAssuranceLevel1 :
isAAL1 = true
case identity . AuthenticatorAssuranceLevel2 :
isAAL2 = true
}
}
if isAAL1 && isAAL2 {
s . AuthenticatorAssuranceLevel = identity . AuthenticatorAssuranceLevel2
} else if isAAL1 {
s . AuthenticatorAssuranceLevel = identity . AuthenticatorAssuranceLevel1
}
}
Authentication Methods (AMR)
The AMR array tracks all authentication methods used in the session:
type AuthenticationMethod struct {
Method identity . CredentialsType
AAL identity . AuthenticatorAssuranceLevel
CompletedAt time . Time
Provider string
Organization string
}
Example AMR
{
"authentication_methods" : [
{
"method" : "password" ,
"aal" : "aal1" ,
"completed_at" : "2024-01-15T09:30:00Z"
},
{
"method" : "totp" ,
"aal" : "aal2" ,
"completed_at" : "2024-01-15T09:31:00Z"
}
]
}
Recording authentication
func ( s * Session ) CompletedLoginFor (
method identity . CredentialsType ,
aal identity . AuthenticatorAssuranceLevel ,
) {
s . CompletedLoginForMethod ( AuthenticationMethod {
Method : method ,
AAL : aal ,
CompletedAt : time . Now (). UTC (),
})
}
Session devices
Kratos tracks device information for each session:
type Device struct {
ID uuid . UUID
SessionID uuid . UUID
IPAddress * string
UserAgent * string
Location * string
CreatedAt time . Time
UpdatedAt time . Time
}
Device data is captured from HTTP requests:
func ( s * Session ) SetSessionDeviceInformation ( r * http . Request ) {
device := Device {
SessionID : s . ID ,
IPAddress : new ( httpx . ClientIP ( r )),
}
agent := r . Header [ "User-Agent" ]
if len ( agent ) > 0 {
device . UserAgent = new ( strings . Join ( agent , " " ))
}
// Cloudflare geolocation headers
if r . Header . Get ( "Cf-Ipcity" ) != "" {
loc := r . Header . Get ( "Cf-Ipcity" ) + ", " +
r . Header . Get ( "Cf-Ipcountry" )
device . Location = & loc
}
s . Devices = append ( s . Devices , device )
}
Session lifespan
Sessions have configurable lifespans:
session :
lifespan : 720h # 30 days
earliest_possible_extend : 1h
Extending sessions
Sessions can be extended:
func ( s * Session ) Refresh ( ctx context . Context , c lifespanProvider ) * Session {
s . ExpiresAt = time . Now (). Add ( c . SessionLifespan ( ctx )). UTC ()
return s
}
Refresh windows
To prevent unnecessary database writes, sessions are only refreshed when needed:
func ( s * Session ) CanBeRefreshed (
ctx context . Context ,
c refreshWindowProvider ,
) bool {
return s . ExpiresAt .
Add ( - c . SessionRefreshMinTimeLeft ( ctx )).
Before ( time . Now ())
}
Session whoami
The /sessions/whoami endpoint returns current session information:
Request
Browser (cookie)
API (bearer token)
API (custom header)
curl "https://kratos-public/sessions/whoami" \
--cookie "ory_kratos_session=..."
Response
{
"id" : "9f425a8d-7efc-4768-8f23-7647a74fdf13" ,
"active" : true ,
"expires_at" : "2024-02-15T09:30:00Z" ,
"authenticated_at" : "2024-01-15T09:30:00Z" ,
"authenticator_assurance_level" : "aal1" ,
"authentication_methods" : [
{
"method" : "password" ,
"aal" : "aal1" ,
"completed_at" : "2024-01-15T09:30:00Z"
}
],
"issued_at" : "2024-01-15T09:30:00Z" ,
"identity" : {
"id" : "7b9f3e2a-5c1d-4f8e-9a3b-2d6c8e4f7a9b" ,
"schema_id" : "default" ,
"traits" : {
"email" : "[email protected] "
},
"state" : "active"
}
}
The active field in the JSON response is computed dynamically based on the session’s expiry time and identity state.
Session caching
The whoami endpoint supports caching:
session :
whoami :
caching :
enabled : true
max_age : 60s
When enabled, responses include:
Ory-Session-Cache-For : 60
Session caching improves performance but may serve stale session data. Use shorter cache durations for security-sensitive applications.
Session context
Sessions can be included in request context for middleware:
func ( h * Handler ) IsAuthenticated (
wrap http . HandlerFunc ,
onUnauthenticated http . HandlerFunc ,
) http . HandlerFunc {
return func ( w http . ResponseWriter , r * http . Request ) {
sess , err := h . r . SessionManager (). FetchFromRequest ( ctx , r )
if err != nil {
if onUnauthenticated != nil {
onUnauthenticated ( w , r )
return
}
// Handle error
}
wrap ( w , r . WithContext ( context . WithValue ( ctx , sessionKey , sess )))
}
}