fix: a /refresh carried by the auth.cookie session cookie rewrites that cookie, so an HttpOnly session survives the rotation

8e4b863 answered a cookie-carried refresh in the body only and blacklisted the old jti, so an HttpOnly cookie (golem15.sociallogin token_cookie) kept a dead token. Now the cookie named auth.cookie.name gets the rotated token and the body is {}; bearer and auth_token refreshes are unchanged, and refusals write no cookie.
This commit is contained in:
Jakub Zych
2026-10-22 23:39:18 +02:00
parent a484d0e9a2
commit 846087db45
5 changed files with 367 additions and 27 deletions

View File

@@ -229,6 +229,32 @@ func SessionToken(r *http.Request) string {
return ""
}
// SessionTokenCookie names the session cookie that supplied the token
// SessionToken returns, for a handler that writes that cookie back (POST
// /refresh rewrites it with the rotated token). It is "" when the bearer
// header supplied the token or the request carries none.
func SessionTokenCookie(r *http.Request) string {
if r == nil || bearerToken(r) != "" {
return ""
}
for _, name := range sessionCookieNames {
if c, err := r.Cookie(name); err == nil && strings.TrimSpace(c.Value) != "" {
return name
}
}
return ""
}
// bearerToken returns the trimmed token of r's Authorization bearer header,
// "" when there is none.
func bearerToken(r *http.Request) string {
h := strings.TrimSpace(r.Header.Get("Authorization"))
if token, ok := strings.CutPrefix(h, "Bearer "); ok {
return strings.TrimSpace(token)
}
return ""
}
// sessionTokens returns every distinct session JWT r carries, in the order
// the "jwt" guard tries them: the Authorization bearer header, then each
// session cookie. Empty values are skipped.
@@ -239,10 +265,7 @@ func sessionTokens(r *http.Request) []string {
out = append(out, v)
}
}
h := strings.TrimSpace(r.Header.Get("Authorization"))
if token, ok := strings.CutPrefix(h, "Bearer "); ok {
add(token)
}
add(bearerToken(r))
for _, name := range sessionCookieNames {
if c, err := r.Cookie(name); err == nil {
add(c.Value)