v1.0.3

Verification Flow

Last updated


This page lists the checks Verify() runs on a request, in order, and the response when each one fails.

Reading Credentials


CredentialLookup order
Access Token1. Cookie access_token (AccessTokenCookieKey) 2. Authorization: Bearer <token>
Refresh ID1. Header X-Refresh-ID 2. Cookie refresh_id (RefreshIdCookieKey)
Device fingerprintSee Device Fingerprint

Check Order


#CheckOn failure
1An Access Token is presentWith a Refresh ID → Transparent Refresh; with neither → 401 unauthorized
2Redis revoke:<accessToken> does not existExists → 401 revoked; Redis error → 500 failed_to_get
3Signing method is ECDSA and the signature verifies with the public key400 data_invalid
4Not expired (exp)Expired → Transparent Refresh
5nbf is not later than now400 data_invalid
6iat is not more than 5 minutes in the future400 data_invalid
7Claim refresh_id equals the request's Refresh ID400 data_invalid
8Claim fp equals this request's fingerprint400 data_invalid
9Redis jti:<jti> exists400 data_invalid

When every check passes, the result is 200 with Data set to the Auth restored from the claims.

Key Behaviors


  • An Access Token needs its Refresh ID: step 7 requires the claim to match the request, so a request with Authorization but no Refresh ID fails.
  • Expiry wins over other errors: when the signature error message contains expired, the flow refreshes instead of returning 400.
  • Revocation is keyed by the Access Token string: it revokes that token, not the user.

Example


  1. result := auth.Verify(w, r)
  2. switch {
  3. case result.Success:
  4. log.Printf("user %s", result.Data.ID)
  5. case result.ErrorTag == "revoked":
  6. http.Error(w, "session revoked", result.StatusCode)
  7. default:
  8. http.Error(w, result.Error, result.StatusCode)
  9. }

Verify may write cookies and headers (on refresh), so call it before writing the response body. See Status Codes and Error Tags for the full mapping.
中文