gincloudflareaccess

package module
v0.2.4 Latest Latest
Warning

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

Go to latest
Published: Dec 5, 2022 License: MIT Imports: 11 Imported by: 0

README

gin-cloudflare-access

Documentation Go Report Card CircleCI Coverage Status

A middleware plugin for securing a Gin application behind Cloudflare Access authentication.

Installation

go get github.com/fabiofenoglio/gin-cloudflare-access

Quickstart

package main

import (
	"net/http"

	gincloudflareaccess "github.com/fabiofenoglio/gin-cloudflare-access"
	"github.com/gin-gonic/gin"
)

func main() {

	cfAccess := gincloudflareaccess.NewCloudflareAccessMiddleware(&gincloudflareaccess.Config{
		TeamDomain: "myorganization",
		ValidAudiences: []string{
			"123123123123123123123123123123123123123",
		},
	})

	r := gin.Default()

	// plug in authenticator at the root level
	r.Use(cfAccess.AuthenticationMiddleware())

	r.GET("/ping", func(c *gin.Context) {
		c.String(http.StatusOK, "pong")
	})

	// require authenticated users for all routes under /secured
	authorized := r.Group("/secured", cfAccess.RequireAuthenticated())

	authorized.GET("/hello", func(c *gin.Context) {
		principal := gincloudflareaccess.GetPrincipal(c)

		c.JSON(http.StatusOK, "hello "+principal.Identity.Name)
	})

	// run the server and listen on http://localhost:9000
	err := r.Run(":9000")
	if err != nil {
		panic(err)
	}
}

Configure routes

Require authentication for a route or a group of routes
cfAccess := gincloudflareaccess.NewCloudflareAccessMiddleware(&gincloudflareaccess.Config{
	// ...
})

r := gin.Default()

// plug in authenticator at the root level
r.Use(cfAccess.AuthenticationMiddleware())

// this route will NOT require authentication.
r.GET("/ping", func(c *gin.Context) {
	c.String(http.StatusOK, "pong")
})

// this route WILL require authentication
r.GET("/whoami", cfAccess.RequireAuthenticated(), func(c *gin.Context) {
	c.String(http.StatusOK, "you are a valid user")
})

// ALL routes under /secured/** will require authentication
authorized := r.Group("/secured", cfAccess.RequireAuthenticated())

authorized.GET("/hello", func(c *gin.Context) {
	principal := gincloudflareaccess.GetPrincipal(c)

	c.JSON(http.StatusOK, "hello "+principal.Identity.Name)
})

// ...
Require membership to one or more LDAP groups for one or more routes
cfAccess := gincloudflareaccess.NewCloudflareAccessMiddleware(&gincloudflareaccess.Config{
	// ...
})

r := gin.Default()

// plug in authenticator at the root level
r.Use(cfAccess.AuthenticationMiddleware())

// ALL routes under /only-administrators/** will be restricted
// to members of administrators@organization.com
//
// You can also use .RequireAllGroups(...) or .RequireAnyGroup(...)
authorized := r.Group("/only-administrators", cfAccess.RequireGroup("administrators@organization.com"))

authorized.GET("/hello", func(c *gin.Context) {
	// ...
})

// ...
Require a custom check for a route or a group of routes
cfAccess := gincloudflareaccess.NewCloudflareAccessMiddleware(&gincloudflareaccess.Config{
	// ...
})

r := gin.Default()

// plug in authenticator at the root level
r.Use(cfAccess.AuthenticationMiddleware())

// ALL routes under /only-fabio/** will be protected by this custom check
authorized := r.Group("/only-fabio", cfAccess.Require(func(c *gin.Context, principal *gincloudflareaccess.CloudflareAccessPrincipal) error {
	if principal == nil || principal.Identity.Name != "Fabio" {
		return errors.New("you are not my true father!")
	}
	return nil
}))

authorized.GET("/hello", func(c *gin.Context) {
	// ...
})

// ...

Manual helpers

Retrieve the authenticated principal
r.GET("/hello", func(c *gin.Context) {
	principal := gincloudflareaccess.GetPrincipal(c)

	c.JSON(http.StatusOK, "hello "+principal.Identity.Name)
})
Manually check if authenticated user belong to LDAP groups
r.GET("/hello", func(c *gin.Context) {
	
	inGroup := gincloudflareaccess.PrincipalInGroup(c, "somegroup@organization.com")
	
	inAllGroups := gincloudflareaccess.PrincipalInAllGroups(c, []string{
		"group1@organization.com",
		"group2@organization.com",
		"groupid00X",
	})

	inAnyGroup := gincloudflareaccess.PrincipalInAnyGroups(c, []string{
		"group0@organization.com",
		"group1@organization.com",
	})

	// ...
})

Customize middleware behavior

Customize error response
cfAccess := gincloudflareaccess.NewCloudflareAccessMiddleware(&gincloudflareaccess.Config{
	TeamDomain: "myorganization",
	ValidAudiences: []string{
		"123123123123123123123123123123123123123",
	},
	
	// Whenever a request is blocked because of invalid or missing authentication,
	// LDAP group conditions not met or custom checks failing,
	// a default error response will be returned in JSON.
	//
	// You can change the way these errors are handled by providing a ErrorResponseHandler.
	// it should call a finalization method such as AbortWithStatusJSON.
	//
	// The ErrorResponseHandler function will be invoked with the request context,
	// the status error (either 401 or 403) and a non-nil error.
	ErrorResponseHandler: func(c *gin.Context, status int, err error) {
		c.AbortWithStatusJSON(
			status,
			fmt.Sprintf("customized error response (original error: %v)", err),
		)
	},
})
Customize token lookup
cfAccess := gincloudflareaccess.NewCloudflareAccessMiddleware(&gincloudflareaccess.Config{
	TeamDomain: "myorganization",
	ValidAudiences: []string{
		"123123123123123123123123123123123123123",
	},
	
	// If for some reason you want to provide the Access header
	// under a different header or with a different mechanism,
	// you can provide the TokenExtractFunc parameter.
	//
	// The function should look for an authorization token wherever you need
	// in the request, and return it.
	// If no token was found you should return an empty string and a nil error.
	// The request will be aborted if the function returns a non-nil error.
	TokenExtractFunc: func(c *gin.Context) (string, error) {
		h := c.Request.Header.Get("X-Custom-Auth-Header")
		if h != "" {
			return h, nil
		}
		cookie, err := c.Request.Cookie("X-Auth-Cookie")
		if cookie != nil && err != nil {
			return cookie.Value, nil
		}
		return "", nil
	},
})
Customize caching
cfAccess := gincloudflareaccess.NewCloudflareAccessMiddleware(&gincloudflareaccess.Config{
TeamDomain: "myorganization",
ValidAudiences: []string{
"123123123123123123123123123123123123123",
},

// By default principals authenticated from a token are cached in memory
// for a short duration.
// You can disable the caching mechanism by providing the DisableCache parameter.
DisableCache: false,

// By default principals authenticated from a token are cached in memory
// for 5 minutes.
// You can change this duration with the CacheTTL parameter.
CacheTTL: 2 * time.Minute,
})
Mock for development purposes

You can provide a custom AuthenticationFunc if you want to mock authentication for development purposes.

settings := &gincloudflareaccess.Config{
	TeamDomain: "myorganization",
	ValidAudiences: []string{
		"123123123123123123123123123123123123123",
	},
}

if (inDevelopment) {
	settings.AuthenticationFunc = func(ctx context.Context, _ string) (*CloudflareAccessPrincipal, error) {
		return &CloudflareAccessPrincipal{
			Identity: &CloudflareIdentity{
				Email: "user@mock.com",
				Name:  "some mocked user",
				Groups: []CloudflareIdentityGroup{
					{
						Id:    "group0",
						Name:  "Some Group",
						Email: "somegroup@mock.com",
					},
				},
			},
			Email: "user@mock.com",
		}, nil
	}
}

cfAccess := gincloudflareaccess.NewCloudflareAccessMiddleware(settings)

You might also pass both AuthenticationFunc and TokenExtractFunc to have a more dynamic mocking logic:

settings := &gincloudflareaccess.Config{
	TeamDomain: "myorganization",
	ValidAudiences: []string{
		"123123123123123123123123123123123123123",
	},
}

if (inDevelopment) {
	settings.TokenExtractFunc = func(c *gin.Context) (string, error) {
		// the content of X-Mocked-Auth will be passed as 'inputFromHeader' to the AuthenticationFunc
		return c.Request.Header.Get("X-Mocked-Auth"), nil
	}
	
	settings.AuthenticationFunc = func(ctx context.Context, inputFromHeader string) (*CloudflareAccessPrincipal, error) {
		return &CloudflareAccessPrincipal{
			Identity: &CloudflareIdentity{
				Email: inputFromHeader + "@mock.com",
				Name:  "user " + inputFromHeader,
				Groups: []CloudflareIdentityGroup{
					{
						Id:    "group0",
						Name:  "Some Group",
						Email: "somegroup@mock.com",
					},
				},
			},
			Email: inputFromHeader + "@mock.com",
		}, nil
	}
}

cfAccess := gincloudflareaccess.NewCloudflareAccessMiddleware(settings)

Full example

package main

import (
	"errors"
	"fmt"
	"net/http"
	"time"

	gincloudflareaccess "github.com/fabiofenoglio/gin-cloudflare-access"
	"github.com/gin-gonic/gin"
)

func main() {

	cfAccess := gincloudflareaccess.NewCloudflareAccessMiddleware(&gincloudflareaccess.Config{
		// TeamDomain is the name of your team.
		//
		// it's the third-level domain of your authentication portal,
		// for instance if your login page is https://organization.cloudflareaccess.com
		// then your TeamDomain is "organization"{
		TeamDomain: "organization",

		// Every Access Policy created under the Access or Team portal
		// will come with a specific Audience Tag.
		//
		// You should provide at least one audience tag
		// but you can support as many policies as you want by providing
		// multiple audience tags.
		ValidAudiences: []string{
			"123123123123123123123123123123123123123",
			"456456456456456456456456456456456456456",
		},

		// By default principals authenticated from a token are cached in memory
		// for a short duration.
		// You can disable the caching mechanism by providing the DisableCache parameter.
		DisableCache: false,

		// By default principals authenticated from a token are cached in memory
		// for 5 minutes.
		// You can change this duration with the CacheTTL parameter.
		CacheTTL: 2 * time.Minute,

		// If for some reason you want to provide the Access header
		// under a different header or with a different mechanism,
		// you can provide the TokenExtractFunc parameter.
		//
		// The function should look for an authorization token wherever you need
		// in the request, and return it.
		// If no token was found you should return an empty string and a nil error.
		// The request will be aborted if the function returns a non-nil error.
		TokenExtractFunc: func(c *gin.Context) (string, error) {
			h := c.Request.Header.Get("X-Custom-Auth-Header")
			if h != "" {
				return h, nil
			}
			cookie, err := c.Request.Cookie("X-Auth-Cookie")
			if cookie != nil && err != nil {
				return cookie.Value, nil
			}
			return "", nil
		},

		// Whenever a request is blocked because of invalid or missing authentication,
		// LDAP group conditions not met or custom checks failing,
		// a default error response will be returned in JSON.
		//
		// You can change the way these errors are handled by providing a ErrorResponseHandler.
		// it should call a finalization method such as AbortWithStatusJSON.
		//
		// The ErrorResponseHandler function will be invoked with the request context,
		// the status error (either 401 or 403) and a non-nil error.
		ErrorResponseHandler: func(c *gin.Context, status int, err error) {
			c.AbortWithStatusJSON(
				status,
				fmt.Sprintf("customized error response (original error: %v)", err),
			)
		},
	})

	r := gin.Default()

	// plug in authenticator at the root level
	// this middleware will read the authorization header or cookies
	// and, if provided, will validate and authenticate the user.
	//
	// invalid credentials and expired tokens will cause an immediate abort.
	//
	// note that, by itself, this middleware does not prevent
	// unauthenticated access nor perform any check on the authentication result
	// other than blocking invalid credentials.
	// additionals check have to be enabled with the .Require...() middlewares
	// that you'll see in the following lines.
	r.Use(cfAccess.AuthenticationMiddleware())

	// this route will not require authentication
	r.GET("/ping", func(c *gin.Context) {
		c.String(http.StatusOK, "pong")
	})

	// let's declare a sample handler to be reused from the following routes
	helloHandler := func(c *gin.Context) {
		// you can retrieve the principal from the gin.Context using GetPrincipal
		// mind that GetPrincipal may return nil for unauthenticated requests
		principal := gincloudflareaccess.GetPrincipal(c)

		// reply with details about the authenticated principal
		c.JSON(http.StatusOK, principal)
	}

	// require authenticated users for all routes under /secured/**
	// by plugging in the RequireAuthenticated middleware
	//
	// note that as other middlewares, .RequireAuthenticated() can be applied to a single route,
	// to a route group or to the whole router
	authorized := r.Group("/secured", cfAccess.RequireAuthenticated())

	// this routes will require authentication
	// (inherited from the 'authorized' route group)
	authorized.GET("/some-protected-route", helloHandler)
	authorized.GET("/other-protected-route", helloHandler)

	// this route will require a custom condition to be evaluated on each request
	//
	// the .Require() middleware can be used to implements custom checks:
	// it receives the request context and the authenticated principals
	// and it can return a non-nil error to abort the request.
	//
	// when the provided function returns an error,
	// the default behavior for Forbidden requests executes, so
	// if a ErrorResponseHandler has been provided it will be
	// invoked with the returned error and a 403 status code.
	//
	// note that as other middlewares, .Require() can be applied to a single route,
	// to a route group or to the whole router
	r.GET("/require-custom", cfAccess.Require(func(c *gin.Context, principal *gincloudflareaccess.CloudflareAccessPrincipal) error {
		if principal == nil {
			return errors.New("auth required")
		}
		if c.Request.Header.Get("X-Mock-Allow") != principal.Identity.Email {
			return errors.New("required custom header not valid")
		}
		return nil
	}), helloHandler)

	// this route will require authenticated users belonging to
	// a specific LDAP group.
	//
	// note that as other middlewares, .RequireGroup() can be applied to a single route,
	// to a route group or to the whole router
	r.GET("/require-group", cfAccess.RequireGroup("group0@organization.com"), helloHandler)

	// this route will require authenticated users belonging to
	// everyone of the specified LDAP groups.
	//
	// note that as other middlewares, .RequireAllGroups() can be applied to a single route,
	// to a route group or to the whole router
	r.GET("/require-all-groups", cfAccess.RequireAllGroups([]string{
		"group0@organization.com",
		"group1@organization.com",
	}), helloHandler)

	// this route will require authenticated users belonging to
	// at least one of the specified LDAP groups.
	//
	// note that as other middlewares, .RequireAnyGroup() can be applied to a single route,
	// to a route group or to the whole router
	r.GET("/require-any-group", cfAccess.RequireAnyGroup([]string{
		"group1@organization.com",
		"groupX@organization.com",
	}), helloHandler)

	// this route will require authentication
	r.GET("/auth-demo", cfAccess.RequireAuthenticated(), func(c *gin.Context) {
		// you can retrieve the principal with the GetPrincipal method.
		// mind that GetPrincipal may return nil for unauthenticated requests
		principal := gincloudflareaccess.GetPrincipal(c)

		if principal == nil {
			panic("didn't expect a nil principal")
		}

		// you can manually check if the user belongs to
		// a/all/any specified LDAP groups with the helper methods:
		inGroup := gincloudflareaccess.PrincipalInGroup(c, "somegroup@organization.com")
		if !inGroup {
			panic("go away")
		}
	})

	// run the server and listen on http://localhost:9000
	err := r.Run(":9000")
	if err != nil {
		panic(err)
	}
}

Available data for authenticated principals

{
    "token":{
        "iss":"https://organization.cloudflareaccess.com",
        "aud":[
            "456456456456456456456456456456456456456456"
        ],
        "sub":"79ea41a5-d90c-45b0-83b7-98bab753c982",
        "exp":"2022-01-23T10:30:51+01:00",
        "iat":"2022-01-22T10:30:51+01:00",
        "email":"user@organization.com",
        "identity_nonce":"dskgwjegowegjo",
        "country":"IT"
    },
    "identity":{
        "id":"1231231241241212312",
        "name":"User Name",
        "email":"user@organization.com",
        "user_uuid":"79ea41a5-d90c-45b0-83b7-98bab753c982",
        "account_id":"cee91dbebfad4e93be5df3616215e207",
        "ip":"1.2.3.4",
        "auth_status":"NONE",
        "common_name":"",
        "service_token_id":"",
        "service_token_status":false,
        "is_warp":false,
        "is_gateway":false,
        "version":0,
        "device_sessions":{},
        "iat":1642843851,
        "idp":{
            "id":"891cfb5e-7de3-43e4-9929-4ae34ab6e110",
            "type":"google-apps"
        },
        "geo":{
            "country":"IT"
        },
        "groups":[
            {
                "id":"f81e269a598341f8807028463abb6eea",
                "name":"Administrators",
                "email":"administrators@organization.com"
            },
            {
                "id":"865c98799d304008b6258b736321b395",
                "name":"Support",
                "email":"support@organization.com"
            }
        ]
    },
    "email":"user@organization.com"
}

Documentation

Index

Constants

View Source
const (
	TypeApp = "app"
)

Variables

This section is empty.

Functions

func PrincipalInAllGroups

func PrincipalInAllGroups(c *gin.Context, groups []string) bool

Check if the user authenticated for the current request belongs to every one of the specified LDAP groups

func PrincipalInAnyGroups

func PrincipalInAnyGroups(c *gin.Context, groups []string) bool

Check if the user authenticated for the current request belongs to at least one of some LDAP groups

func PrincipalInGroup

func PrincipalInGroup(c *gin.Context, group string) bool

Check if the user authenticated for the current request belongs to a specific LDAP group

Types

type CloudflareAccessMiddleware

type CloudflareAccessMiddleware interface {

	// AuthenticationMiddleware will build a middleware
	// that reads the authorization header or cookies
	// and, if provided, will validate and authenticate the user.
	//
	// invalid credentials and expired tokens will cause an immediate abort.
	//
	// note that, by itself, this middleware does not prevent
	// unauthenticated access nor perform any check on the authentication result
	// other than blocking invalid credentials.
	// Additional check have to be enabled with the .Require...() middlewares
	//
	// note that as every middleware, AuthenticationMiddleware() can be applied to a single route,
	// to a route group or to the whole router.
	// However, you should plug it in at the router level
	// with something like r.Use(cfAccess.AuthenticationMiddleware())
	AuthenticationMiddleware() gin.HandlerFunc

	// RequireAuthenticated will build a middleware restricting access
	// to authenticated users.
	//
	// note that as every middleware, RequireAuthenticated() can be applied to a single route,
	// to a route group or to the whole router
	RequireAuthenticated() gin.HandlerFunc

	// RequireGroup will build a middleware restricting access
	// to users belonging to a specific LDAP group
	//
	// note that as every middleware, RequireGroup() can be applied to a single route,
	// to a route group or to the whole router
	RequireGroup(group string) gin.HandlerFunc

	// RequireAnyGroup will build a middleware restricting access
	// to users belonging to at least one of some LDAP groups
	//
	// note that as every middleware, RequireAnyGroup() can be applied to a single route,
	// to a route group or to the whole router
	RequireAnyGroup(groups []string) gin.HandlerFunc

	// RequireAllGroups will build a middleware restricting access
	// to users belonging to every one of the specified LDAP groups
	//
	// note that as every middleware, RequireAllGroups() can be applied to a single route,
	// to a route group or to the whole router
	RequireAllGroups(groups []string) gin.HandlerFunc

	// Require will build a middleware restricting access
	// by evaluating a specific custom for every request.
	//
	// the .Require() middleware can be used to implement custom checks:
	// it receives the request context and the authenticated principals
	// and it can return a non-nil error to abort the request.
	//
	// when the provided function returns an error,
	// the default behavior for forbidden requests executes, so
	// if a ErrorResponseHandler has been provided it will be
	// invoked with the returned error and a 403 status code.
	//
	// note that as every middleware, .Require() can be applied to a single route,
	// to a route group or to the whole router
	Require(check func(c *gin.Context, principal *CloudflareAccessPrincipal) error) gin.HandlerFunc
}

CloudflareAccessMiddleware is a middleware builder providing middlewares for authentication, authorization and principals management.

func NewCloudflareAccessMiddleware

func NewCloudflareAccessMiddleware(config *Config) CloudflareAccessMiddleware

NewCloudflareAccessMiddleware builds a CloudflareAccessMiddleware with the provided configuration.

type CloudflareAccessPrincipal

type CloudflareAccessPrincipal struct {
	Token      *CloudflareJWT      `json:"token"`
	Identity   *CloudflareIdentity `json:"identity"`
	Email      string              `json:"email"`
	CommonName string              `json:"common_name"`
	Details    interface{}
}

func GetPrincipal

func GetPrincipal(c *gin.Context) *CloudflareAccessPrincipal

GetPrincipal extracts the current principal from the request context.

Note that the principal can be nil if no authentication was provided.

func (*CloudflareAccessPrincipal) IsApplication added in v0.2.0

func (t *CloudflareAccessPrincipal) IsApplication() bool

IsApplication returns True if the principal of the token is an application authenticated via a service token or certificate.

func (*CloudflareAccessPrincipal) IsUser added in v0.2.0

func (t *CloudflareAccessPrincipal) IsUser() bool

IsUser returns True if the principal of the token is a human user with a valid email.

type CloudflareIdentity

type CloudflareIdentity struct {
	Id                 string                          `json:"id"`
	Name               string                          `json:"name"`
	Email              string                          `json:"email"`
	UserUUID           string                          `json:"user_uuid"`
	AccountId          string                          `json:"account_id"`
	IP                 string                          `json:"ip"`
	AuthStatus         string                          `json:"auth_status"`
	CommonName         string                          `json:"common_name"`
	ServiceTokenId     string                          `json:"service_token_id"`
	ServiceTokenStatus bool                            `json:"service_token_status"`
	IsWarp             bool                            `json:"is_warp"`
	IsGateway          bool                            `json:"is_gateway"`
	Version            int                             `json:"version"`
	DeviceSessions     map[string]interface{}          `json:"device_sessions"`
	IssuedAt           int                             `json:"iat"`
	Idp                *CloudflareIdentityProvider     `json:"idp"`
	Geographical       *CloudflareIdentityGeographical `json:"geo"`
	Groups             []CloudflareIdentityGroup       `json:"groups"`
}

CloudflareIdentity is the model for the user identity

type CloudflareIdentityGeographical

type CloudflareIdentityGeographical struct {
	Country string `json:"country"`
}

type CloudflareIdentityGroup

type CloudflareIdentityGroup struct {
	Id    string `json:"id"`
	Name  string `json:"name"`
	Email string `json:"email"`
}

type CloudflareIdentityProvider

type CloudflareIdentityProvider struct {
	Id   string `json:"id"`
	Type string `json:"type"`
}

type CloudflareJWT

type CloudflareJWT struct {
	RawToken      *oidc.IDToken `json:"-"`
	Issuer        string        `json:"iss"`
	Audience      []string      `json:"aud"`
	Subject       string        `json:"sub"`
	Expiry        time.Time     `json:"exp"`
	IssuedAt      time.Time     `json:"iat"`
	Email         string        `json:"email"`
	IdentityNonce string        `json:"identity_nonce"`
	Country       string        `json:"country"`
	Type          string        `json:"type"`
	CommonName    string        `json:"common_name"`
}

func (*CloudflareJWT) IsApplication added in v0.2.0

func (t *CloudflareJWT) IsApplication() bool

IsApplication returns True if the principal of the token is an application authenticated via a service token or certificate.

func (*CloudflareJWT) IsUser added in v0.2.0

func (t *CloudflareJWT) IsUser() bool

IsUser returns True if the principal of the token is a human user with a valid email.

type Config

type Config struct {

	// TeamDomain is the name of your team.
	//
	// it's the third-level domain of your authentication portal,
	// for instance if your login page is https://organization.cloudflareaccess.com
	// then your TeamDomain is "organization"
	TeamDomain string

	// Every Access Policy created under the Access or Team portal
	// will come with a specific Audience Tag.
	//
	// You should provide at least one audience tag,
	// but you can support as many policies as you want by providing
	// multiple audience tags.
	ValidAudiences []string

	// If for some reason you want to provide the Access header
	// under a different header or with a different mechanism,
	// you can provide the TokenExtractFunc parameter.
	//
	// The function should look for an authorization token wherever you need
	// in the request, and return it.
	// If no token was found you should return an empty string and a nil error.
	// The request will be aborted if the function returns a non-nil error.
	TokenExtractFunc func(c *gin.Context) (string, error)

	// If for some reason you want to customize the token verification and principal builder
	// instead of performing the standard JWK verification process,
	// you can provide the AuthenticationFunc parameter.
	//
	// The function should accept a raw token, validate it and return a corresponding
	// *CloudflareAccessPrincipal in case the token is valid.
	// If token is invalid it should return a non-nil error.
	AuthenticationFunc func(context.Context, string) (*CloudflareAccessPrincipal, error)

	// By default, principals authenticated from a token are cached in memory
	// for a short duration.
	// You can disable the caching mechanism by providing the DisableCache parameter.
	DisableCache bool

	// By default, principals authenticated from a token are cached in memory
	// for 5 minutes.
	// You can change this duration with the CacheTTL parameter.
	CacheTTL time.Duration

	// Whenever a request is blocked because of invalid or missing authentication,
	// LDAP group conditions not met or custom checks failing,
	// a default error response will be returned in JSON.
	//
	// You can change the way these errors are handled by providing a ErrorResponseHandler.
	// it should call a finalization method such as AbortWithStatusJSON.
	//
	// The ErrorResponseHandler function will be invoked with the request context,
	// the status error (either 401 or 403) and a non-nil error.
	ErrorResponseHandler func(c *gin.Context, status int, err error)

	// You can provide a function to load additional details from the principal.
	//
	// The loaded data will be attached as "Detail" field for the principal and
	// kept in cache.
	DetailsFetcher func(c *gin.Context, principal *CloudflareAccessPrincipal) (interface{}, error)
	// contains filtered or unexported fields
}

Config holds the basic configuration options for the CloudflareAccess integration.

at least a valid TeamDomain and a ValidAudiences are required.

Jump to

Keyboard shortcuts

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