Categorygithub.com/velmie/x/authentication
package
1.0.0
Repository: https://github.com/velmie/x.git
Documentation: pkg.go.dev

# README

Authentication

This package provides functionality for authentication tasks.

Short introduction

The working horse of this package is the Authenticate(token string) (Entity, error) method which accepts arbitrary string token and returns a set of attributes represented by the type Entity map[string]any type.

JWT authentication

The package provides JSON Web Token (JWT) authentication capabilities through the ViaJWT struct which depends upon a JWT parser and key source for parsing and validating the token respectively.

Here is an example of how to use the ViaJWT:

package main

import (
	"context"
	"crypto"
	"fmt"
	"github.com/golang-jwt/jwt/v5"
	"github.com/velmie/x/authentication"
)

func main() {

	parser := authentication.NewJWTv5Parser(jwt.NewParser())
	keySource := authentication.KeySourceFunc(myPublicKey)

	jwtAuth := authentication.NewViaJWT(parser, keySource)

	const token = "eyJhbGciOiJFUzI1NiIsImtpZCI6IjB5eHE4Z0ViOThTUkxTWGlrNDFZY3p4UGhPcVZ5Ulc0ZG16VjBydVBtbnciLCJ0eXAiOiJ" +
		"KV1QifQ.eyJpYXQiOjE2ODMxMTU2MTQsIm5hbWUiOiJKb2huIERvZSIsInN1YiI6IjEyMzQ1Njc4OTAifQ.i7vDxB_hUE-08n3vUCngyyiG6" +
		"qvvwR5rl1-vDsyqs5MwuXM8wIuAmPITJ3-JY7wCOxy-oSdZ-_joutqdy80mLg"

	entity, err := jwtAuth.Authenticate(context.Background(), token)
	if err != nil {
		// handle error
		// ...
	}
	fmt.Println(entity["name"]) // John Doe
	//...

}

func myPublicKey(kid string) (crypto.PublicKey, error) {
	var key crypto.PublicKey
	// do something to get the key using the kid (key id)
	// ...
	return key, nil
}

Key Sources

The package provides different key source implementations to fetch public keys for JWT token validation.

KeySourceFunc

KeySourceFunc is a function type that implements the KeySource interface. This allows you to use a simple function as a key source without having to create a separate struct implementing the KeySource interface.

KeySourceMap

KeySourceMap is a map of key IDs (kids) to public keys, implementing the KeySource interface.

KeySourceSingle

KeySourceSingle is a struct that implements the KeySource interface and returns a single public key, regardless of the input key ID (kid). This implementation is useful when you have a single public key for token validation.

Usage
// Create a KeySourceMap with key IDs and their corresponding public keys
keySource := authentication.KeySourceMap{
	"keyID1": publicKey1,
	"keyID2": publicKey2,
}

// Create a KeySourceSingle with a single public key
keySource := authentication.KeySourceSingle{
	PublicKey: publicKey,
}

// Use a custom KeySourceFunc
keySource := authentication.KeySourceFunc(func(ctx context.Context, kid string) (crypto.PublicKey, error) {
	// Fetch the public key based on the key ID (kid)
})

JWKS (JSON Web Key Set) Key Source

KeySourceJWKS is an implementation of the KeySource interface that fetches public keys from a remote JSON Web Key Set (JWKS) endpoint. JWKS is a JSON object that represents a set of keys containing the public keys used to verify any JSON Web Token (JWT) issued by the authorization server.

Features

  • Fetches public keys from a remote JWKS endpoint using HTTP requests.
  • Supports request rate limiting and warning functions.
  • Allows fetching on unknown key IDs (kids) or not requesting on unknown kids, depending on configuration.
  • Caches fetched keys to avoid unnecessary requests.
  • Automatically refreshes the keys when the cache expires.
Usage
package main

import (
	"context"
	"fmt"
	"github.com/golang-jwt/jwt/v5"
	"github.com/velmie/x/authentication"
	"net/http"
	"time"
)

func main() {

	parser := authentication.NewJWTv5Parser(jwt.NewParser())

	jwksOptions := authentication.JWKSOptions{
		Client:              http.DefaultClient, // customize http client (default: http.DefaultClient)
		RefreshInterval:     3 * time.Minute,    // customize keys refresh interval (default: 1 * time.Minute)
		RequestOnUnknownKID: true,               // whether to request unknown kid from JWKS endpoint (default: false)
		WarnFunc: func(msg string) {
			fmt.Printf("WARN: %s\n", msg) // optional warning function (default: nil)
		},
	}

	// enable rate limiting for requests to JWKS endpoint (default: no limit)
	jwksOptions.SetRefreshRateLimit(5, time.Minute) // 5 requests per minute

	keySource := authentication.NewKeySourceJWKS("https://example.com/.well-known/jwks.json", &jwksOptions)

	jwtAuth := authentication.NewViaJWT(parser, keySource)

	const token = "eyJhbGciOiJFUzI1NiIsImtpZCI6IjB5eHE4Z0ViOThTUkxTWGlrNDFZY3p4UGhPcVZ5Ulc0ZG16VjBydVBtbnciLCJ0eXAiOiJ" +
		"KV1QifQ.eyJpYXQiOjE2ODMxMTU2MTQsIm5hbWUiOiJKb2huIERvZSIsInN1YiI6IjEyMzQ1Njc4OTAifQ.i7vDxB_hUE-08n3vUCngyyiG6" +
		"qvvwR5rl1-vDsyqs5MwuXM8wIuAmPITJ3-JY7wCOxy-oSdZ-_joutqdy80mLg"

	entity, err := jwtAuth.Authenticate(context.Background(), token)
	if err != nil {
		// handle error
		// ...
	}
	fmt.Println(entity["name"]) // John Doe
	//...

}