Skip to content

Commit 7fef1e0

Browse files
committed
fix(authflow): evaluate max_age from per-session auth time, not global LastLogin
The max_age check in trySessionLogin compared now against ui.LastLogin, a single global per-identity row rewritten to now() by EVERY interactive login from ANY browser, device, or session. A fresh login on a second device therefore satisfied an RP's max_age re-authentication demand for a stale session on the first device. The per-session, per-client authentication timestamp already exists and is populated (storage.ClientAuthState.AuthenticatedAt, written on direct login and carried across for SSO). Use it, falling back to ui.LastLogin only when the session has no client state.
1 parent ab64ed7 commit 7fef1e0

2 files changed

Lines changed: 13 additions & 3 deletions

File tree

server/authflow/sessionlogin.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,19 @@ func (h *Handler) trySessionLoginWithSession(ctx context.Context, r *http.Reques
6262
return false
6363
}
6464

65-
// Check max_age: if the user's last authentication is too old, force re-auth.
65+
// Check max_age against THIS session's authentication time for this client,
66+
// not the global per-identity LastLogin. ui.LastLogin is a single global row
67+
// rewritten to now() by EVERY interactive login from ANY browser/device, so a
68+
// fresh login on a second device would otherwise satisfy an RP's max_age
69+
// re-authentication demand for a stale session on the first. The per-session,
70+
// per-client timestamp already exists (ClientAuthState.AuthenticatedAt,
71+
// carried across for SSO above) and is guaranteed non-nil here.
6672
if authReq.MaxAge >= 0 {
67-
if now.Sub(ui.LastLogin) > time.Duration(authReq.MaxAge)*time.Second {
73+
authenticatedAt := ui.LastLogin
74+
if cs := session.ClientStates[authReq.ClientID]; cs != nil && !cs.AuthenticatedAt.IsZero() {
75+
authenticatedAt = cs.AuthenticatedAt
76+
}
77+
if now.Sub(authenticatedAt) > time.Duration(authReq.MaxAge)*time.Second {
6878
return false
6979
}
7080
}

server/authflow/sessionlogin_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -662,7 +662,7 @@ func setupSessionWithIdentity(t *testing.T, s *sessionTestServer, now time.Time,
662662
ID: nonce, Secret: nonce,
663663
ClientStates: map[string]*storage.ClientAuthState{
664664
"client-1": {
665-
AuthenticatedAt: now.Add(-1 * time.Minute),
665+
AuthenticatedAt: lastLogin,
666666
LastActivity: now.Add(-1 * time.Minute),
667667
},
668668
},

0 commit comments

Comments
 (0)