Categorygithub.com/gofiber/contrib/jwt
modulepackage
1.0.10
Repository: https://github.com/gofiber/contrib.git
Documentation: pkg.go.dev

# README


id: jwt

JWT

Release Discord Test Security Linter

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

Note: Requires Go 1.19 and above

Install

This middleware supports Fiber v1 & v2, install accordingly.

go get -u github.com/gofiber/fiber/v2
go get -u github.com/gofiber/contrib/jwt
go get -u github.com/golang-jwt/jwt/v5

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
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. The default value ("Bearer") will only be used in conjuction with the default TokenLookup value."Bearer"
KeyFuncfunc() jwt.KeyfuncKeyFunc defines a user-defined function that supplies the public key for a token validation.jwtKeyFunc
JWKSetURLs[]stringA slice of unique JSON Web Key (JWK) Set URLs to used to parse JWTs.nil

HS256 Example

package main

import (
	"time"

	"github.com/gofiber/fiber/v2"

	jwtware "github.com/gofiber/contrib/jwt"
	"github.com/golang-jwt/jwt/v5"
)

func main() {
	app := fiber.New()

	// Login route
	app.Post("/login", login)

	// Unauthenticated route
	app.Get("/", accessible)

	// JWT Middleware
	app.Use(jwtware.New(jwtware.Config{
		SigningKey: jwtware.SigningKey{Key: []byte("secret")},
	}))

	// Restricted Routes
	app.Get("/restricted", restricted)

	app.Listen(":3000")
}

func login(c *fiber.Ctx) error {
	user := c.FormValue("user")
	pass := c.FormValue("pass")

	// Throws Unauthorized error
	if user != "john" || pass != "doe" {
		return c.SendStatus(fiber.StatusUnauthorized)
	}

	// Create the Claims
	claims := jwt.MapClaims{
		"name":  "John Doe",
		"admin": true,
		"exp":   time.Now().Add(time.Hour * 72).Unix(),
	}

	// Create token
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)

	// Generate encoded token and send it as response.
	t, err := token.SignedString([]byte("secret"))
	if err != nil {
		return c.SendStatus(fiber.StatusInternalServerError)
	}

	return c.JSON(fiber.Map{"token": t})
}

func accessible(c *fiber.Ctx) error {
	return c.SendString("Accessible")
}

func restricted(c *fiber.Ctx) error {
	user := c.Locals("user").(*jwt.Token)
	claims := user.Claims.(jwt.MapClaims)
	name := claims["name"].(string)
	return c.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"

	"github.com/golang-jwt/jwt/v5"

	jwtware "github.com/gofiber/contrib/jwt"
)

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
)

func main() {
	app := fiber.New()

	// Just as a demo, generate a new private/public key pair on each run. See note above.
	rng := rand.Reader
	var err error
	privateKey, err = rsa.GenerateKey(rng, 2048)
	if err != nil {
		log.Fatalf("rsa.GenerateKey: %v", err)
	}

	// Login route
	app.Post("/login", login)

	// Unauthenticated route
	app.Get("/", accessible)

	// JWT Middleware
	app.Use(jwtware.New(jwtware.Config{
		SigningKey: jwtware.SigningKey{
			JWTAlg: jwtware.RS256,
			Key:    privateKey.Public(),
		},
	}))

	// Restricted Routes
	app.Get("/restricted", restricted)

	app.Listen(":3000")
}

func login(c *fiber.Ctx) error {
	user := c.FormValue("user")
	pass := c.FormValue("pass")

	// Throws Unauthorized error
	if user != "john" || pass != "doe" {
		return c.SendStatus(fiber.StatusUnauthorized)
	}

	// Create the Claims
	claims := jwt.MapClaims{
		"name":  "John Doe",
		"admin": true,
		"exp":   time.Now().Add(time.Hour * 72).Unix(),
	}

	// Create token
	token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims)

	// Generate encoded token and send it as response.
	t, err := token.SignedString(privateKey)
	if err != nil {
		log.Printf("token.SignedString: %v", err)
		return c.SendStatus(fiber.StatusInternalServerError)
	}

	return c.JSON(fiber.Map{"token": t})
}

func accessible(c *fiber.Ctx) error {
	return c.SendString("Accessible")
}

func restricted(c *fiber.Ctx) error {
	user := c.Locals("user").(*jwt.Token)
	claims := user.Claims.(jwt.MapClaims)
	name := claims["name"].(string)
	return c.SendString("Welcome " + name)
}

RS256 Test

The RS256 is actually identical to the HS256 test above.

JWK Set Test

The tests are identical to basic JWT tests above, with exception that JWKSetURLs to valid public keys collection in JSON Web Key (JWK) Set format should be supplied. See RFC 7517.

Custom KeyFunc example

KeyFunc defines a user-defined function that supplies the public key for a token validation. The function shall take care of verifying the signing algorithm and selecting the proper key. A user-defined KeyFunc can be useful if tokens are issued by an external party.

When a user-defined KeyFunc is provided, SigningKey, SigningKeys, and SigningMethod are ignored. This is one of the three options to provide a token validation key. The order of precedence is a user-defined KeyFunc, SigningKeys and SigningKey. Required if neither SigningKeys nor SigningKey is provided. Default to an internal implementation verifying the signing algorithm and selecting the proper key.

package main

import (
	"fmt"
  "github.com/gofiber/fiber/v2"

  jwtware "github.com/gofiber/contrib/jwt"
  "github.com/golang-jwt/jwt/v5"
)

func main() {
	app := fiber.New()

	app.Use(jwtware.New(jwtware.Config{
		KeyFunc: customKeyFunc(),
	}))

	app.Get("/ok", func(c *fiber.Ctx) error {
		return c.SendString("OK")
	})
}

func customKeyFunc() jwt.Keyfunc {
	return func(t *jwt.Token) (interface{}, error) {
		// Always check the signing method
		if t.Method.Alg() != jwtware.HS256 {
			return nil, fmt.Errorf("Unexpected jwt signing method=%v", t.Header["alg"])
		}

		// TODO custom implementation of loading signing key like from a database
    signingKey := "secret"

		return []byte(signingKey), nil
	}
}

# Functions

New ...

# Constants

ES256 represents a public cryptography key generated by a 256 bit ECDSA algorithm.
ES384 represents a public cryptography key generated by a 384 bit ECDSA algorithm.
ES512 represents a public cryptography key generated by a 512 bit ECDSA algorithm.
HS256 represents a public cryptography key generated by a 256 bit HMAC algorithm.
HS384 represents a public cryptography key generated by a 384 bit HMAC algorithm.
HS512 represents a public cryptography key generated by a 512 bit HMAC algorithm.
P256 represents a cryptographic elliptical curve type.
P384 represents a cryptographic elliptical curve type.
P521 represents a cryptographic elliptical curve type.
PS256 represents a public cryptography key generated by a 256 bit RSA algorithm.
PS384 represents a public cryptography key generated by a 384 bit RSA algorithm.
PS512 represents a public cryptography key generated by a 512 bit RSA algorithm.
RS256 represents a public cryptography key generated by a 256 bit RSA algorithm.
RS384 represents a public cryptography key generated by a 384 bit RSA algorithm.
RS512 represents a public cryptography key generated by a 512 bit RSA algorithm.

# Variables

ErrJWTAlg is returned when the JWT header did not contain the expected algorithm.
ErrJWTMissingOrMalformed is returned when the JWT is missing or malformed.

# Structs

Config defines the config for JWT middleware.
SigningKey holds information about the recognized cryptographic keys used to sign JWTs by this program.