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

@@ -30,9 +30,10 @@ var sessionCookieNames = []string{"token", "auth_token"}
// header first, then the token and auth_token cookies. A cookie-only session
// that jwt.auth accepts is served; no credentials stays 401 with the old
// bodies; a bearer header wins over a cookie exactly as on jwt.auth; a
// cookie-carried token is refused for the same reasons as a bearer one; and a
// cookie-carried /refresh answers the new token in the body and sets no
// cookie.
// cookie-carried token is refused for the same reasons as a bearer one; a
// /refresh through the token cookie (the auth.cookie default) gets that
// cookie back with the rotated token and an empty body, and one through
// auth_token gets the rotated token in the body and no cookie.
func TestSessionRoutesAcceptCookies(t *testing.T) {
e := newAdminEnv(t)
@@ -99,19 +100,28 @@ func TestSessionRoutesAcceptCookies(t *testing.T) {
if rec.Code != http.StatusOK {
t.Fatalf("refresh with the %s cookie = %d %s", name, rec.Code, rec.Body.String())
}
var body struct {
Token string `json:"token"`
var next string
if name == "token" {
if rec.Body.String() != `{}` {
t.Fatalf("refresh with the token cookie answered %s", rec.Body.String())
}
next = assertSessionCookie(t, rec, e.cookieConfig(t), 20160*60)
} else {
var body struct {
Token string `json:"token"`
}
if err := json.Unmarshal(rec.Body.Bytes(), &body); err != nil {
t.Fatal(err)
}
next = body.Token
if cookies := rec.Result().Cookies(); len(cookies) != 0 {
t.Fatalf("refresh set cookies %v", cookies)
}
}
if err := json.Unmarshal(rec.Body.Bytes(), &body); err != nil {
t.Fatal(err)
}
if body.Token == "" || body.Token == token {
if next == "" || next == token {
t.Fatalf("refresh answered %s", rec.Body.String())
}
if cookies := rec.Result().Cookies(); len(cookies) != 0 {
t.Fatalf("refresh set cookies %v", cookies)
}
if code := e.fetchCode(t, body.Token); code != http.StatusOK {
if code := e.fetchCode(t, next); code != http.StatusOK {
t.Fatalf("fetch with the refreshed token = %d", code)
}
if rec := e.cookieSend(t, http.MethodGet, userFetchPath, name, token, nil); rec.Code != http.StatusUnauthorized {