auth0

package module
v1.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 19, 2019 License: MIT Imports: 9 Imported by: 0

README

Build Coverage Godoc Go report License
Build Status Coverage Status GoDoc Report Cart MIT License

Contributors

Thanks goes to these wonderful people who contribute(d) or maintain(ed) this repo (emoji key):

Conrad Sopala
Conrad Sopala

🚧 👀
Yannick Heinrich
Yannick Heinrich

🚧 💻
Hao Chau
Hao Chau

💻
Max Ekman
Max Ekman

💻
Tony Jia
Tony Jia

💻

Go-Auth0


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

This repo is supported and maintained by Community Developers, not Auth0. For more information about different support levels check https://auth0.com/docs/support/matrix .

Getting started

Installation

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

Usage

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(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.

Usage

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)
}

Validating a token outside an HTTP request

Sometimes a token is received from something that is not an HTTP request (such as a GRPC call) when a token must be validated in those cases, use ValidateToken directly

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 = retrieveToken() // Retrieves the token through custom logic, such as for example fetching it from GRPC metadata
if err := validator.ValidateToken(token); err != nil {
	fmt.Println("Cannot validate token because of", err)
}

Contribute

Feel like contributing to this repo? We're glad to hear that! Before you start contributing please visit our Contributing Guideline .

Here you can also find the PR template to fill once creating a PR. It will automatically appear once you open a pull request.

Issues Reporting

Spotted a bug or any other kind of issue? We're just humans and we're always waiting for constructive feedback! Check our section on how to report issues!

Here you can also find the Issue template to fill once opening a new issue. It will automatically appear once you create an issue.

Repo Community

Feel like PRs and issues are not enough? Want to dive into further discussion about the tool? We created topics for each Auth0 Community repo so that you can join discussion on stack available on our repos. Here it is for this one: go-auth0

License

This project is licensed under the MIT license. See the LICENSE file for more info.

What is Auth0?

Auth0 helps you to:

  • Add authentication with multiple authentication sources, either social like

    • Google
    • Facebook
    • Microsoft
    • Linkedin
    • GitHub
    • Twitter
    • Box
    • Salesforce
    • etc.

    or enterprise identity systems like:

    • Windows Azure AD
    • Google Apps
    • Active Directory
    • ADFS
    • Any SAML Identity Provider
  • Add authentication through more traditional username/password databases

  • Add support for linking different user accounts with the same user

  • Support for generating signed JSON Web Tokens to call your APIs and create user identity flow securely

  • Analytics of how, when and where users are logging in

  • Pull data from other sources and add it to user profile, through JavaScript rules

Create a free Auth0 account

  • Go to Auth0 website
  • Hit the SIGN UP button in the upper-right corner

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrInvalidContentType = errors.New("should have a JSON content type for JWKS endpoint")
	ErrInvalidAlgorithm   = errors.New("algorithm is invalid")
)
View Source
var (
	ErrNoKeyFound = errors.New("no Keys has been found")
	ErrKeyExpired = errors.New("key exists but is expired")

	// Configuring with MaxKeyAgeNoCheck will skip key expiry check
	MaxKeyAgeNoCheck = time.Duration(-1)
	// Configuring with MaxCacheSizeNoCheck will skip key cache size check
	MaxCacheSizeNoCheck = -1
)
View Source
var (
	// ErrTokenNotFound is returned by the ValidateRequest if the token was not
	// found in the request.
	ErrTokenNotFound = errors.New("Token not found")
	// ErrNilRequest is returned by the FromHeader if the request is nil
	ErrNilRequest = errors.New("Request nil")
)
View Source
var (
	// ErrNoJWTHeaders is returned when there are no headers in the JWT.
	ErrNoJWTHeaders = errors.New("No headers in the token")
)

Functions

func FromCookie

func FromCookie(r *http.Request) (*jwt.JSONWebToken, error)

FromCookie returns the JWT when passed in a Cookie as "access_token".

func FromHeader

func FromHeader(r *http.Request) (*jwt.JSONWebToken, error)

FromHeader looks for the request in the authentication header or call ParseMultipartForm if not present. TODO: Implement parsing form data.

func FromParams

func FromParams(r *http.Request) (*jwt.JSONWebToken, error)

FromParams returns the JWT when passed as the URL query param "token".

Types

type Configuration

type Configuration struct {
	// contains filtered or unexported fields
}

Configuration contains all the information about the Auth0 service.

func NewConfiguration

func NewConfiguration(provider SecretProvider, audience []string, issuer string, method jose.SignatureAlgorithm) Configuration

NewConfiguration creates a configuration for server

func NewConfigurationTrustProvider

func NewConfigurationTrustProvider(provider SecretProvider, audience []string, issuer string) Configuration

NewConfigurationTrustProvider creates a configuration for server with no enforcement for token sig alg type, instead trust provider

type JWKClient

type JWKClient struct {
	// contains filtered or unexported fields
}

func NewJWKClient

func NewJWKClient(options JWKClientOptions, extractor RequestTokenExtractor) *JWKClient

NewJWKClient creates a new JWKClient instance from the provided options.

func NewJWKClientWithCache

func NewJWKClientWithCache(options JWKClientOptions, extractor RequestTokenExtractor, keyCacher KeyCacher) *JWKClient

NewJWKClientWithCache creates a new JWKClient instance from the provided options and a custom keycacher interface. Passing nil to keyCacher will create a persistent key cacher

func (*JWKClient) GetKey

func (j *JWKClient) GetKey(ID string) (jose.JSONWebKey, error)

GetKey returns the key associated with the provided ID.

func (*JWKClient) GetSecret

func (j *JWKClient) GetSecret(token *jwt.JSONWebToken) (interface{}, error)

GetSecret implements the GetSecret method of the SecretProvider interface.

type JWKClientOptions

type JWKClientOptions struct {
	URI    string
	Client *http.Client
}

type JWKS

type JWKS struct {
	Keys []jose.JSONWebKey `json:"keys"`
}

type JWTValidator

type JWTValidator struct {
	// contains filtered or unexported fields
}

JWTValidator helps middleware to validate token

func NewValidator

func NewValidator(config Configuration, extractor RequestTokenExtractor) *JWTValidator

NewValidator creates a new validator with the provided configuration.

func (*JWTValidator) Claims

func (v *JWTValidator) Claims(token *jwt.JSONWebToken, values ...interface{}) error

Claims unmarshall the claims of the provided token

func (*JWTValidator) ValidateRequest

func (v *JWTValidator) ValidateRequest(r *http.Request) (*jwt.JSONWebToken, error)

ValidateRequest validates the token within the http request. A default leeway value of one minute is used to compare time values.

func (*JWTValidator) ValidateRequestWithLeeway

func (v *JWTValidator) ValidateRequestWithLeeway(r *http.Request, leeway time.Duration) (*jwt.JSONWebToken, error)

ValidateRequestWithLeeway validates the token within the http request. The provided leeway value is used to compare time values.

func (*JWTValidator) ValidateToken

func (v *JWTValidator) ValidateToken(token *jwt.JSONWebToken) error

func (*JWTValidator) ValidateTokenWithLeeway

func (v *JWTValidator) ValidateTokenWithLeeway(token *jwt.JSONWebToken, leeway time.Duration) error

type KeyCacher

type KeyCacher interface {
	Get(keyID string) (*jose.JSONWebKey, error)
	Add(keyID string, webKeys []jose.JSONWebKey) (*jose.JSONWebKey, error)
}

func NewMemoryKeyCacher

func NewMemoryKeyCacher(maxKeyAge time.Duration, maxCacheSize int) KeyCacher

NewMemoryKeyCacher creates a new Keycacher interface with option to set max age of cached keys and max size of the cache.

type RequestTokenExtractor

type RequestTokenExtractor interface {
	Extract(r *http.Request) (*jwt.JSONWebToken, error)
}

RequestTokenExtractor can extract a JWT from a request.

func FromMultiple

func FromMultiple(extractors ...RequestTokenExtractor) RequestTokenExtractor

FromMultiple combines multiple extractors by chaining.

type RequestTokenExtractorFunc

type RequestTokenExtractorFunc func(r *http.Request) (*jwt.JSONWebToken, error)

RequestTokenExtractorFunc function conforming to the RequestTokenExtractor interface.

func (RequestTokenExtractorFunc) Extract

Extract calls f(r)

type SecretProvider

type SecretProvider interface {
	GetSecret(token *jwt.JSONWebToken) (interface{}, error)
}

SecretProvider will provide everything needed retrieve the secret.

func NewKeyProvider

func NewKeyProvider(key interface{}) SecretProvider

NewKeyProvider provide a simple passphrase key provider.

type SecretProviderFunc

type SecretProviderFunc func(token *jwt.JSONWebToken) (interface{}, error)

SecretProviderFunc simple wrappers to provide secret with functions.

func (SecretProviderFunc) GetSecret

func (f SecretProviderFunc) GetSecret(token *jwt.JSONWebToken) (interface{}, error)

GetSecret implements the SecretProvider interface.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL