Categorygithub.com/paulusrobin/go-auth0
modulepackage
1.0.0
Repository: https://github.com/paulusrobin/go-auth0.git
Documentation: pkg.go.dev

# README

Build Status Coverage Status GoDoc Report Cart MIT License

auth0

auth0 is a package helping to authenticate using the Auth0 service.

Installation

go get github.com/auth0-community/go-auth0

Client Credentials - HS256

Using HS256, the validation key is the secret you retrieve in the dashboard.

// Creates a configuration with the Auth0 information
secret, _ := base64.URLEncoding.DecodeString(os.Getenv("AUTH0_CLIENT_SECRET"))
secretProvider := auth0.NewKeyProvider(secret)
audience := os.Getenv("AUTH0_CLIENT_ID")

configuration := auth0.NewConfiguration(secretProvider, []string{audience}, "https://mydomain.eu.auth0.com/", jose.HS256)
validator := auth0.NewValidator(configuration, nil)

token, err := validator.ValidateRequest(r)

if err != nil {
    fmt.Println("Token is not valid:", token)
}

Client Credentials - RS256

Using RS256, the validation key is the certificate you find in advanced settings

// Extracted from https://github.com/square/go-jose/blob/master/utils.go
// LoadPublicKey loads a public key from PEM/DER-encoded data.
// You can download the Auth0 pem file from `applications -> your_app -> scroll down -> Advanced Settings -> certificates -> download`
func LoadPublicKey(data []byte) (interface{}, error) {
	input := data

	block, _ := pem.Decode(data)
	if block != nil {
		input = block.Bytes
	}

	// Try to load SubjectPublicKeyInfo
	pub, err0 := x509.ParsePKIXPublicKey(input)
	if err0 == nil {
		return pub, nil
	}

	cert, err1 := x509.ParseCertificate(input)
	if err1 == nil {
		return cert.PublicKey, nil
	}

	return nil, fmt.Errorf("square/go-jose: parse error, got '%s' and '%s'", err0, err1)
}
// Create a configuration with the Auth0 information
pem, err := ioutil.ReadFile("path/to/your/cert.pem")
if err != nil {
	panic(err)
}
secret, err := LoadPublicKey(sharedKey)
if err != nil {
	panic(err)
}
secretProvider := auth0.NewKeyProvider(secret)
audience := os.Getenv("AUTH0_CLIENT_ID")

configuration := auth0.NewConfiguration(secretProvider, []string{audience}, "https://mydomain.eu.auth0.com/", jose.RS256)
validator := auth0.NewValidator(configuration, nil)

token, err := validator.ValidateRequest(r)

if err != nil {
    fmt.Println("Token is not valid:", token)
}

API with JWK

client := NewJWKClient(JWKClientOptions{URI: "https://mydomain.eu.auth0.com/.well-known/jwks.json"}, nil)
audience := os.Getenv("AUTH0_CLIENT_ID")
configuration := NewConfiguration(client, []string{audience}, "https://mydomain.eu.auth0.com/", jose.RS256)
validator := NewValidator(configuration, nil)

token, err := validator.ValidateRequest(r)

if err != nil {
    fmt.Println("Token is not valid:", token)
}

Support interface for configurable key cacher

opts := JWKClientOptions{URI: "https://mydomain.eu.auth0.com/.well-known/jwks.json"}
// Creating key cacher with max age of 100sec and max size of 5 entries.
// Defaults to persistent key cacher if not specified when creating a client.
keyCacher := NewMemoryKeyCacher(time.Duration(100) * time.Second, 5)
client := NewJWKClientWithCache(opts, nil, keyCacher)

searchedKey, err := client.GetKey("KEY_ID")

if err != nil {
	fmt.Println("Cannot get key because of", err)
}

Example

Gin

Using Gin and the Auth0 Authorization Extension, you may want to implement the authentication auth like the following:

var auth.AdminGroup string = "my_admin_group"

// Access Control Helper function.
func shouldAccess(wantedGroups []string, groups []interface{}) bool {
 /* Fill depending on your needs */
}

// Wrapping a Gin endpoint with Auth0 Groups.
func Auth0Groups(wantedGroups ...string) gin.HandlerFunc {

	return gin.HandlerFunc(func(c *gin.Context) {

		tok, err := validator.ValidateRequest(c.Request)
		if err != nil {
			c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid token"})
			c.Abort()
			log.Println("Invalid token:", err)
			return
		}

		claims := map[string]interface{}{}
		err = validator.Claims(c.Request, tok, &claims)
		if err != nil {
			c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid claims"})
			c.Abort()
			log.Println("Invalid claims:", err)
			return
		}

		metadata, okMetadata := claims["app_metadata"].(map[string]interface{})
		authorization, okAuthorization := metadata["authorization"].(map[string]interface{})
		groups, hasGroups := authorization["groups"].([]interface{})
		if !okMetadata || !okAuthorization || !hasGroups || !shouldAccess(wantedGroups, groups) {
			c.JSON(http.StatusUnauthorized, gin.H{"error": "need more privileges"})
			c.Abort()
			log.Println("Need more provileges")
			return
		}
		c.Next()
	})
}

// Use it
r.PUT("/news", auth.Auth0Groups(auth.AdminGroup), api.GetNews)

For a sample usage, take a look inside the example directory.

# Packages

No description provided by the author

# Functions

FromHeader looks for the request in the authentication header or call ParseMultipartForm if not present.
FromMultiple combines multiple extractors by chaining.
FromParams returns the JWT when passed as the URL query param "token".
NewConfiguration creates a configuration for server.
NewConfigurationTrustProvider creates a configuration for server with no enforcement for token sig alg type, instead trust provider.
NewJWKClient creates a new JWKClient instance from the provided options.
NewJWKClientWithCache creates a new JWKClient instance from the provided options and a custom keycacher interface.
NewKeyProvider provide a simple passphrase key provider.
NewMemoryKeyCacher creates a new Keycacher interface with option to set max age of cached keys and max size of the cache.
NewValidator creates a new validator with the provided configuration.

# Variables

No description provided by the author
No description provided by the author
No description provided by the author
ErrNoJWTHeaders is returned when there are no headers in the JWT.
No description provided by the author
ErrTokenNotFound is returned by the ValidateRequest if the token was not found in the request.
Configuring with MaxCacheSizeNoCheck will skip key cache size check.
Configuring with MaxKeyAgeNoCheck will skip key expiry check.

# Structs

Configuration contains all the information about the Auth0 service.
No description provided by the author
No description provided by the author
No description provided by the author
JWTValidator helps middleware to validate token.

# Interfaces

No description provided by the author
RequestTokenExtractor can extract a JWT from a request.
SecretProvider will provide everything needed retrieve the secret.

# Type aliases

RequestTokenExtractorFunc function conforming to the RequestTokenExtractor interface.
SecretProviderFunc simple wrappers to provide secret with functions.