Install the jwt library
mainTo use the jwt library in your Go project, ensure you are using Go version 1.17 or higher and run the following command:
go get github.com/cristalhq/jwt/v5repository·main·Indexed 20 days ago
https://github.com/cristalhq/jwtA high-performance, dependency-free JSON Web Token (JWT) library for Go implementing RFC 7519. Designed to be memory and CPU conservative with a concurrent-safe API, it supports HMAC (HS), RSA (RS), RSA-PSS (PS), ECDSA (ES), and EdDSA algorithms. The library provides tools for building, parsing, and verifying tokens through Signer and Verifier interfaces, and allows for the implementation of custom algorithms.
To use the jwt library in your Go project, ensure you are using Go version 1.17 or higher and run the following command:
go get github.com/cristalhq/jwt/v5When using HMAC (HS) algorithms, ensure your signing keys are sufficiently long to prevent brute-force attacks. While short keys are often used in tests or examples for clarity, production environments require high-entropy, long keys.
To generate a secure key, use the jwt.GenerateRandom512Bit function.
// Use this to generate a secure key for production
key := jwt.GenerateRandom512Bit()To create a new JSON Web Token (JWT), use the NewBuilder function followed by the Build method.
NewBuilder(signer, ...opts) where signer is an implementation of the Signer interface. You can optionally provide BuilderOption functions to configure the header.Build(claims) on the builder instance. The claims argument can be a struct (which will be JSON marshaled), a string, or a []byte (treated as pre-marshaled JSON).The Builder is safe for concurrent use.
// Assuming 'signer' is already implemented
builder := jwt.NewBuilder(signer, jwt.WithKeyID("my-key-id"))
type MyClaims struct {
Sub string `json:"sub"`
}
token, err := builder.Build(MyClaims{Sub: "12345"})
if err != nil {
// handle error
}To create a new token, you must first create a Signer using a specific algorithm (e.g., NewSignerHS for HMAC), define your claims (such as RegisteredClaims), and use a Builder to assemble the token.
// create a Signer (HMAC in this example)
key := []byte(`secret`)
signer, err := jwt.NewSignerHS(jwt.HS256, key)
checkErr(err)
// create claims (you can create your own, see: ExampleBuilder_withUserClaims)
claims := &jwt.RegisteredClaims{
Audience: []string{"admin"},
ID: "random-unique-string",
}
// create a Builder
builder := jwt.NewBuilder(signer)
// and build a Token
token, err := builder.Build(claims)
checkErr(err)
// here is token as a string
var _ string = token.String()To validate a token, create a Verifier with the appropriate key and algorithm. You can then parse the token bytes into a new token object, verify its signature, and extract the claims. The library provides methods to parse the full token or just the claims directly.
// create a Verifier (HMAC in this example)
key := []byte(`secret`)
verifier, err := jwt.NewVerifierHS(jwt.HS256, key)
checkErr(err)
// parse and verify a token
tokenBytes := token.Bytes()
newToken, err := jwt.Parse(tokenBytes, verifier)
checkErr(err)
// or just verify it's signature
err = verifier.Verify(newToken)
checkErr(err)
// get Registered claims
var newClaims jwt.RegisteredClaims
errClaims := json.Unmarshal(newToken.Claims(), &newClaims)
checkErr(errClaims)
// or parse only claims
errParseClaims := jwt.ParseClaims(tokenBytes, verifier, &newClaims)
checkErr(errParseClaims)
// verify claims as you wish
var _ bool = newClaims.IsForAudience("admin")
var _ bool = newClaims.IsValidAt(time.Now())The library supports all well-known algorithms, including:
When using Parse, ParseClaims, or ParseNoVerify, the library may return ErrInvalidFormat. This typically occurs if:
eyJ)..) separating header, claims, and signature.The Sign method on an RSAlg instance generates a digital signature for the provided byte slice payload using the configured RSA private key and PKCS#1 v1.5 padding.
signature, err := signer.Sign(payload)
if err != nil {
// handle error
}Use NewSignerRS to create a signer for RSA-based algorithms (RS256, RS384, or RS512). This requires an Algorithm type and a pointer to an rsa.PrivateKey. The signer uses PKCS#1 v1.5 padding.
Supported algorithms:
RS256 (SHA-256)RS384 (SHA-384)RS512 (SHA-512)import (
"crypto/rsa"
"github.com/cristalhq/cristalhq/jwt"
)
// Assuming 'key' is an existing *rsa.PrivateKey
signer, err := jwt.NewSignerRS(jwt.RS256, key)
if err != nil {
// handle error
}Use ParseNoVerify to decode a raw JWT byte slice into a *Token without checking the signature.
Warning: This method does not guarantee the token is authentic or has not been tampered with. Only use this if you specifically need to inspect the header or claims before deciding whether to verify the signature.
token, err := jwt.ParseNoVerify(rawTokenBytes)
if err != nil {
// handle error
}
// token is decoded but NOT verifiedUse NewVerifierEdDSA to create a verifier instance for EdDSA (Ed25519) signatures. You must provide a valid ed25519.PublicKey.
Errors:
ErrNilKey: if the provided key is empty.ErrInvalidKey: if the key length does not match ed25519.PublicKeySize.import (
"crypto/ed25519"
"github.com/cristalhq/cristalhq/jwt"
)
// Assuming you have a valid ed25519 public key
verifier, err := jwt.NewVerifierEdDSA(publicKey)
if err != nil {
// handle error
}Use the following methods to check if a token is valid relative to a specific point in time (now).
IsValidAt(now time.Time) bool: A composite check that returns true only if the token satisfies ExpiresAt, NotBefore, and IssuedAt constraints.IsValidExpiresAt(now time.Time) bool: Returns true if ExpiresAt is nil or if the expiration time is strictly after now.IsValidNotBefore(now time.Time) bool: Returns true if NotBefore is nil or if the not-before time is strictly before now.IsValidIssuedAt(now time.Time) bool: Returns true if IssuedAt is nil or if the issued-at time is strictly before now.