Skip to content

Repository files navigation

JSON Web Tokens

ReleaseDiscordTestSecurityLinter

JWT returns a JSON Web Token (JWT) auth middleware. For valid token, it sets the user in Ctx.Locals and calls next handler. For invalid token, it returns "401 - Unauthorized" error. For missing token, it returns "400 - Bad Request" error.

Special thanks and credits to Echo

Install

This middleware supports Fiber v1 & v2, install accordingly.

go get -u github.com/gofiber/fiber/v2
go get -u github.com/gofiber/jwt/v3
go get -u github.com/golang-jwt/jwt/v4

Signature

jwtware.New(config...jwtware.Config) func(*fiber.Ctx) error

Config

PropertyTypeDescriptionDefault
Filterfunc(*fiber.Ctx) boolDefines a function to skip middlewarenil
SuccessHandlerfunc(*fiber.Ctx) errorSuccessHandler defines a function which is executed for a valid token.nil
ErrorHandlerfunc(*fiber.Ctx, error) errorErrorHandler defines a function which is executed for an invalid token.401 Invalid or expired JWT
SigningKeyinterface{}Signing key to validate token. Used as fallback if SigningKeys has length 0.nil
SigningKeysmap[string]interface{}Map of signing keys to validate token with kid field usage.nil
SigningMethodstringSigning method, used to check token signing method. Possible values: HS256, HS384, HS512, ES256, ES384, ES512, RS256, RS384, RS512"HS256"
ContextKeystringContext key to store user information from the token into context."user"
Claimsjwt.ClaimClaims are extendable claims data defining token content.jwt.MapClaims{}
TokenLookupstringTokenLookup is a string in the form of <source>:<name> that is used"header:Authorization"
AuthSchemestringAuthScheme to be used in the Authorization header."Bearer"
KeySetURLstringKeySetURL location of JSON file with signing keys.""
KeyRefreshSuccessHandlerfunc(j *KeySet)KeyRefreshSuccessHandler defines a function which is executed for a valid refresh of signing keys.nil
KeyRefreshErrorHandlerfunc(j *KeySet, err error)KeyRefreshErrorHandler defines a function which is executed for an invalid refresh of signing keys.nil
KeyRefreshInterval*time.DurationKeyRefreshInterval is the duration to refresh the JWKs in the background via a new HTTP request.nil
KeyRefreshRateLimit*time.DurationKeyRefreshRateLimit limits the rate at which refresh requests are granted.nil
KeyRefreshTimeout*time.DurationKeyRefreshTimeout is the duration for the context used to create the HTTP request for a refresh of the JWKs.1min
KeyRefreshUnknownKIDboolKeyRefreshUnknownKID indicates that the JWKs refresh request will occur every time a kid that isn't cached is seen.false

HS256 Example

package main
import (
"time""github.com/gofiber/fiber/v2"
jwtware "github.com/gofiber/jwt/v3""github.com/golang-jwt/jwt/v4"
)
funcmain() {
app:=fiber.New()
// Login routeapp.Post("/login", login)
// Unauthenticated routeapp.Get("/", accessible)
// JWT Middlewareapp.Use(jwtware.New(jwtware.Config{
SigningKey: []byte("secret"),
}))
// Restricted Routesapp.Get("/restricted", restricted)
app.Listen(":3000")
}
funclogin(c*fiber.Ctx) error {
user:=c.FormValue("user")
pass:=c.FormValue("pass")
// Throws Unauthorized errorifuser!="john"||pass!="doe" {
returnc.SendStatus(fiber.StatusUnauthorized)
}
// Create tokentoken:=jwt.New(jwt.SigningMethodHS256)
// Set claimsclaims:=token.Claims.(jwt.MapClaims)
claims["name"] ="John Doe"claims["admin"] =trueclaims["exp"] =time.Now().Add(time.Hour*72).Unix()
// Generate encoded token and send it as response.t, err:=token.SignedString([]byte("secret"))
iferr!=nil {
returnc.SendStatus(fiber.StatusInternalServerError)
}
returnc.JSON(fiber.Map{"token": t})
}
funcaccessible(c*fiber.Ctx) error {
returnc.SendString("Accessible")
}
funcrestricted(c*fiber.Ctx) error {
user:=c.Locals("user").(*jwt.Token)
claims:=user.Claims.(jwt.MapClaims)
name:=claims["name"].(string)
returnc.SendString("Welcome "+name)
}

HS256 Test

Login using username and password to retrieve a token.

curl --data "user=john&pass=doe" http://localhost:3000/login

Response

{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0NjE5NTcxMzZ9.RB3arc4-OyzASAaUhC2W3ReWaXAt_z2Fd3BN4aWTgEY"
}

Request a restricted resource using the token in Authorization request header.

curl localhost:3000/restricted -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0NjE5NTcxMzZ9.RB3arc4-OyzASAaUhC2W3ReWaXAt_z2Fd3BN4aWTgEY"

Response

Welcome John Doe

RS256 Example

package main
import (
"crypto/rand""crypto/rsa""log""time""github.com/gofiber/fiber/v2"
jwtware "github.com/gofiber/jwt/v3""github.com/golang-jwt/jwt/v4"
)
var (
// Obviously, this is just a test example. Do not do this in production.// In production, you would have the private key and public key pair generated// in advance. NEVER add a private key to any GitHub repo.privateKey*rsa.PrivateKey
)
funcmain() {
app:=fiber.New()
// Just as a demo, generate a new private/public key pair on each run. See note above.rng:=rand.ReadervarerrerrorprivateKey, err=rsa.GenerateKey(rng, 2048)
iferr!=nil {
log.Fatalf("rsa.GenerateKey: %v", err)
}
// Login routeapp.Post("/login", login)
// Unauthenticated routeapp.Get("/", accessible)
// JWT Middlewareapp.Use(jwtware.New(jwtware.Config{
SigningMethod: "RS256",
SigningKey: privateKey.Public(),
}))
// Restricted Routesapp.Get("/restricted", restricted)
app.Listen(":3000")
}
funclogin(c*fiber.Ctx) error {
user:=c.FormValue("user")
pass:=c.FormValue("pass")
// Throws Unauthorized errorifuser!="john"||pass!="doe" {
returnc.SendStatus(fiber.StatusUnauthorized)
}
// Create tokentoken:=jwt.New(jwt.SigningMethodRS256)
// Set claimsclaims:=token.Claims.(jwt.MapClaims)
claims["name"] ="John Doe"claims["admin"] =trueclaims["exp"] =time.Now().Add(time.Hour*72).Unix()
// Generate encoded token and send it as response.t, err:=token.SignedString(privateKey)
iferr!=nil {
log.Printf("token.SignedString: %v", err)
returnc.SendStatus(fiber.StatusInternalServerError)
}
returnc.JSON(fiber.Map{"token": t})
}
funcaccessible(c*fiber.Ctx) error {
returnc.SendString("Accessible")
}
funcrestricted(c*fiber.Ctx) error {
user:=c.Locals("user").(*jwt.Token)
claims:=user.Claims.(jwt.MapClaims)
name:=claims["name"].(string)
returnc.SendString("Welcome "+name)
}

RS256 Test

The RS256 is actually identical to the HS256 test above.

JWKs Test

The tests are identical to basic JWT tests above, with exception that KeySetURL to valid public keys collection in JSON format should be supplied.

About

🧬 JWT middleware for Fiber

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages