fix(09): WR-14 let logout revoke an expired token that is still refreshable and always clear the cookie
This commit is contained in:
@@ -51,6 +51,42 @@ func RefreshAudienceFor(ctx context.Context, users UserProvider, secret, tokenSt
|
||||
return refreshAudience(secret, tokenString, audience, false, refreshTTL, bl, grace, issuerURL, check)
|
||||
}
|
||||
|
||||
// VerifyRefreshableClaimsAudience verifies the signature and the required
|
||||
// audience of a token without checking exp, and accepts it while its refresh
|
||||
// window (iat plus refreshTTL) is open: exactly the tokens RefreshAudience still
|
||||
// reissues. It lets a logout revoke a token whose access lifetime has passed but
|
||||
// which could still be refreshed. It returns the subject, iat, exp and jti; a
|
||||
// token with no jti, no iat or no exp is refused.
|
||||
func VerifyRefreshableClaimsAudience(tokenString, secret, audience string, refreshTTL time.Duration) (sub string, iat, exp time.Time, jti string, err error) {
|
||||
if strings.TrimSpace(audience) == "" {
|
||||
return "", time.Time{}, time.Time{}, "", errors.New("bouncer: jwt audience is empty")
|
||||
}
|
||||
if strings.TrimSpace(secret) == "" {
|
||||
return "", time.Time{}, time.Time{}, "", errors.New("bouncer: jwt secret is empty")
|
||||
}
|
||||
parser := jwt.NewParser(jwt.WithValidMethods([]string{"HS256"}), jwt.WithoutClaimsValidation())
|
||||
claims := jwt.MapClaims{}
|
||||
if _, err := parser.ParseWithClaims(tokenString, claims, func(*jwt.Token) (any, error) {
|
||||
return []byte(secret), nil
|
||||
}); err != nil {
|
||||
return "", time.Time{}, time.Time{}, "", mapJWTError(err)
|
||||
}
|
||||
if !audienceMatches(claims, audience) {
|
||||
return "", time.Time{}, time.Time{}, "", errors.New(msgBadSignature)
|
||||
}
|
||||
sub = subject(claims)
|
||||
jti, _ = claims["jti"].(string)
|
||||
iat, iatOK := claimTime(claims, "iat")
|
||||
exp, expOK := claimTime(claims, "exp")
|
||||
if sub == "" || jti == "" || !iatOK || !expOK {
|
||||
return "", time.Time{}, time.Time{}, "", errors.New(msgRequiredClaims)
|
||||
}
|
||||
if time.Now().After(iat.Add(refreshTTL)) {
|
||||
return "", time.Time{}, time.Time{}, "", errors.New("Token has expired and can no longer be refreshed")
|
||||
}
|
||||
return sub, iat, exp, jti, nil
|
||||
}
|
||||
|
||||
// refreshAudience holds the shared refresh flow. check, when non-nil, runs
|
||||
// after every token-only check and immediately before minting.
|
||||
func refreshAudience(secret, tokenString, audience string, allowMissing bool, refreshTTL time.Duration, bl BlacklistStore, grace time.Duration, issuerURL string, check func(sub string, iat time.Time) error) (string, error) {
|
||||
|
||||
Reference in New Issue
Block a user