package jwt import ( "time" "github.com/golang-jwt/jwt" "github.com/google/uuid" "github.com/pkg/errors" ) // NewAccess generates a new JWT access token for the specified subject (user). // // Parameters: // - subjectID: The user ID or subject identifier to associate with the token // - fresh: If true, marks the token as "fresh" for sensitive operations. // Fresh tokens are typically required for actions like changing passwords // or email addresses. The token remains fresh until FreshExpireAfter minutes. // - rememberMe: If true, the token is persistent (TTL="exp") and will be stored // with an expiration date. If false, it's session-only (TTL="session") and // expires when the browser closes. // // Returns: // - tokenString: The signed JWT token string // - expiresIn: Unix timestamp when the token expires // - err: Any error encountered during token generation func (gen *TokenGenerator) NewAccess( subjectID int, fresh bool, rememberMe bool, ) (tokenString string, expiresIn int64, err error) { issuedAt := time.Now().Unix() expiresAt := issuedAt + (gen.accessExpireAfter * 60) var freshExpiresAt int64 if fresh { freshExpiresAt = issuedAt + (gen.freshExpireAfter * 60) } else { freshExpiresAt = issuedAt } var ttl string if rememberMe { ttl = "exp" } else { ttl = "session" } token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{ "iss": gen.trustedHost, "scope": "access", "ttl": ttl, "jti": uuid.New(), "iat": issuedAt, "exp": expiresAt, "fresh": freshExpiresAt, "sub": subjectID, }) signedToken, err := token.SignedString([]byte(gen.secretKey)) if err != nil { return "", 0, errors.Wrap(err, "token.SignedString") } return signedToken, expiresAt, nil } // NewRefresh generates a new JWT refresh token for the specified subject (user). // Refresh tokens are used to obtain new access tokens without re-authentication. // // Parameters: // - subjectID: The user ID or subject identifier to associate with the token // - rememberMe: If true, the token is persistent (TTL="exp") and will be stored // with an expiration date. If false, it's session-only (TTL="session") and // expires when the browser closes. // // Returns: // - tokenStr: The signed JWT token string // - exp: Unix timestamp when the token expires // - err: Any error encountered during token generation func (gen *TokenGenerator) NewRefresh( subjectID int, rememberMe bool, ) (tokenStr string, exp int64, err error) { issuedAt := time.Now().Unix() expiresAt := issuedAt + (gen.refreshExpireAfter * 60) var ttl string if rememberMe { ttl = "exp" } else { ttl = "session" } token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{ "iss": gen.trustedHost, "scope": "refresh", "ttl": ttl, "jti": uuid.New(), "iat": issuedAt, "exp": expiresAt, "sub": subjectID, }) signedToken, err := token.SignedString([]byte(gen.secretKey)) if err != nil { return "", 0, errors.Wrap(err, "token.SignedString") } return signedToken, expiresAt, nil }