Skip to main content
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:
session/session.go
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.

Token format

Session tokens have the format:
ory_st_<random-string>
Example:
ory_st_MP2YWEMeM8MxjkGKpH4dqOQ4Q4DlSPaj

Token storage

Tokens are stored:
1

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
2

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:
  1. Looking up the token in the database
  2. Checking if the session is active
  3. Verifying the session hasn’t expired
  4. Confirming the identity is active
session/session.go
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:
LevelDescriptionExamples
AAL0No authenticationInitial state
AAL1Single-factor authenticationPassword, Social sign-in, Passkey
AAL2Multi-factor authenticationPassword + TOTP, Password + WebAuthn

AAL calculation

AAL is determined by the authentication methods used:
session/session.go
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:
session/session.go
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:
session/session.go
type Device struct {
    ID        uuid.UUID
    SessionID uuid.UUID
    IPAddress *string
    UserAgent *string
    Location  *string
    CreatedAt time.Time
    UpdatedAt time.Time
}

Capturing device information

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:
kratos.yml
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

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:
kratos.yml
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)))
    }
}

Build docs developers (and LLMs) love