Skip to content

auth: verifier accepts future-issued tokens without nbf #1710

Description

@alexandru-calinoiu

Summary

auth.APIKeyTokenVerifier.Verify accepts a correctly signed token whose iat (Issued At) claim is far in the future when the token omits nbf. This appears to be a behavior regression from the switch to github.com/golang-jwt/jwt/v5.

Reproduction

I verified this against livekit/livekit-server:latest (v1.13.5) running locally in development mode. I signed this token with the server’s configured API secret:

futureIssuedAt := time.Now().Add(2 * time.Hour)
token, err := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.RegisteredClaims{
    Issuer:    "devkey",
    Subject:   "future-iat-test",
    IssuedAt:  jwt.NewNumericDate(futureIssuedAt),
    ExpiresAt: jwt.NewNumericDate(futureIssuedAt.Add(time.Hour)),
    // nbf intentionally omitted
}).SignedString([]byte("secret"))

The token also carried the roomList grant. An immediate request to RoomService.ListRooms returned 200 OK, despite the iat being two hours ahead.

Impact

This is not an unsigned-token or external-forgery vulnerability: producing the token still requires the API secret. However, a trusted/custom token issuer can create a future-dated token that is usable immediately, rather than at its stated issuance time. Normal tokens minted by auth.AccessToken.ToJWT are protected because they set nbf = now; the gap affects custom minters that set iat but omit nbf.

Proposed fix

Add jwt.WithIssuedAt() to the existing jwt.ParseWithClaims options in auth/verifier.go, next to jwt.WithLeeway(tokenLeeway) and jwt.WithExpirationRequired().

jwt/v5 does not validate iat by default. WithIssuedAt() validates the claim when present, while preserving compatibility with tokens that omit this optional claim. The existing one-minute leeway would continue to cover small clock skew.

Please add a regression test for a correctly signed token with an iat two hours in the future and no nbf.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions