authn

package
v0.0.0-...-c55d386 Latest Latest
Warning

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

Go to latest
Published: Sep 26, 2024 License: Apache-2.0 Imports: 23 Imported by: 6

README

Authn: Robust JWT Verification for the Grafana Ecosystem

This library provides a robust and flexible way to verify JSON Web Tokens (JWTs) within the Grafana ecosystem.

Features:

  • Generic JWT verifier with support for custom claims
  • Specialized verifiers for Grafana ID Tokens and Access Tokens
  • Composable gRPC interceptors for retrieving, sending then verifying tokens in request metadata

Token verifier

This package will handle retrival and caching of jwks. It was desing to be generic over "Custom claims" so that we are not only restricted to the current structure of id tokens. This means that the parsed claims will contain standard jwts claims such as aud, exp etc plus specified custom claims.

package main

import (
	"context"
	"log"

	"github.com/grafana/authlib/authn"
)

type CustomClaims struct{}

func main() {
	verifier := authn.NewVerifier[CustomClaims](authn.VerifierConfig{
		AllowedAudiences: []string{},
	}, authn.TokenTypeID, authn.NewKeyRetiever(KeyRetrieverConfig{SigningKeysURL: "<jwks url>"}))

	claims, err := verifier.Verify(context.Background(), "<token>")

	if err != nil {
		log.Fatal("failed to verify id token: ", err)
	}

	log.Println("Claims: ", claims)
}

The verifier is generic over jwt.Claims. Most common use cases will be to either verify Grafana issued ID-Token or Access token. For those we have AccessTokenVerifier and IDTokenVerifier. These two structures are just simple wrappers around Verifier with expected claims.

gRPC interceptors

This package simplifies the implementation of authentication within your gRPC services operating within the Grafana ecosystem.

Key Components:

  • Client-Side Interceptor: Request access tokens from the Token Signing Server and enrich your gRPC requests with necessary metadata. This modular interceptor allows you to customize the added metadata based on your specific service requirements (e.g: user ID token, requested namespace).
  • Server-Side Authenticator: Easily verify the validity of access tokens (and optionally ID tokens) against the Token Signing Server's public keys. This authenticator integrates directly with the standard grpc-ecosystem/go-grpc-middleware/auth interceptor for straightforward implementation.
Example 1: Full authentication example with ID and Access Tokens

In this first example:

  • We configure the client interceptor to interact with the MyService gRPC service. This interceptor uses its own myClientToken to request an access token from the token signing service at "/v1/sign-access-token". The requested access token will grant access to the MyService for the stacks-22 namespace. The interceptor will also add the incoming user's ID token to the metadata, along with the query namespace using the X-Namespace key. We assume that MyService requires this additional Namespace metadata to determine which tenant is being queried.
  • On the server side, we set up the interceptor for the MyService service. This interceptor extracts the access and ID tokens from the gRPC metadata. It then populates the application context with an AuthInfo object. Functions within MyService can use this AuthInfo object to access information about the caller (such as their permissions).

Diagram:

full authentication flow

Client side:

import (
	authnlib "github.com/grafana/authlib/authn"
	authzlib "github.com/grafana/authlib/authz"
	"github.com/grafana/authlib/claims"
	"google.golang.org/grpc"
)

// idTokenExtractor is a helper function to get the user ID Token from context
func idTokenExtractor(ctx context.Context) (string, error) {
	authInfo, ok := claims.From(ctx)
	if !ok {
		return "", fmt.Errorf("no claims found")
	}

	extra := authInfo.GetExtra()
	if token, exists := extra["id-token"]; exists && len(token) != 0 && token[0] != "" {
		return token[0], nil
	}

	return "", fmt.Errorf("id-token not found")
}

// namespaceExtractor is a helper function used to populate gRPC metadata with the namespace
func namespaceExtractor(ctx context.Context) (key string, values []string, err error) {
	return authzlib.DefaultNamespaceMetadataKey, []string{"stacks-22"}, nil
}

func main() {
	// The client interceptor authenticates requests to the gRPC server using
	// the provided TokenExchangeConfig. It automatically handles token exchange
	// and injects the ID token along with the extracted StackID into the request metadata.
	clientInt, err := authnlib.NewGrpcClientInterceptor(
		&authnlib.GrpcClientConfig{
			TokenClientConfig: &authnlib.TokenExchangeConfig{
				Token:            "myClientToken",
				TokenExchangeURL: "https://token-signer/v1/sign-access-token",
			},
			TokenRequest: &authnlib.TokenExchangeRequest{
				Namespace: "stacks-22",
				Audiences: []string{"MyService"},
			},
		},
		authnlib.WithIDTokenExtractorOption(idTokenExtractor),
		authnlib.WithMetadataExtractorOption(namespaceExtractor),
	)
	if err != nil {
		os.Exit(1)
	}

	conn, err := grpc.NewClient(
		"myService:10000",
		grpc.WithUnaryInterceptor(clientInt.UnaryClientInterceptor),
		grpc.WithStreamInterceptor(clientInt.StreamClientInterceptor),
	)

	// ...
}

Server side:

import (
	authnlib "github.com/grafana/authlib/authn"
	"github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/auth"
	"google.golang.org/grpc"
)

func main() (*authnlib.GrpcAuthenticator, error) {
	// A grpc service
	service := MyService{}

	// For remote communication, this authenticator ensures secure access by:
	//  1. Validating ID and access tokens against the signing server's keys.
	//  2. Verifying this service's identifier is present in the access token's
	//     audience list, confirming intended authorization.
	authenticator := authnlib.NewGrpcAuthenticator(
		&authnlib.GrpcAuthenticatorConfig{
			KeyRetrieverConfig: authnlib.KeyRetrieverConfig{
				SigningKeysURL: "https://token-signer/v1/keys",
			},
			VerifierConfig: authnlib.VerifierConfig{
				AllowedAudiences: []string{"MyService"},
			},
		},
		authnlib.WithIDTokenAuthOption(true),
	)

	// Create a new grpc server
	server = grpc.NewServer(
		grpc.ChainUnaryInterceptor(
			auth.UnaryServerInterceptor(authenticator.Authenticate),
		),
		grpc.ChainStreamInterceptor(
			auth.StreamServerInterceptor(authenticator.Authenticate),
		),
	)
	server.RegisterService(&authzv1.MyService_ServiceDesc, service)

	// ...
}
Example 2: Custom authentication flow with ID Token only and a custom metadata

In this second example:

  • We configure the client interceptor to interact with the MyService gRPC service. This interceptor does not request an access token to interact with the MyService service but still adds the incoming user's ID token to the metadata, along with the origin using the X-Origin key. We assume that MyService requires this additional origin metadata to determine where the call is coming from and enforce some additional rules.
  • On the server side, we set up the interceptor for the MyService service. This interceptor solely extracts the ID tokens from the gRPC metadata. It then populates the application context with an AuthInfo object. Functions within MyService can use this AuthInfo object to access information about the user.

Diagram:

custom authentication flow

Client side:

import (
	context
	errors

	authnlib "github.com/grafana/authlib/authn"
	authzlib "github.com/grafana/authlib/authz"
	"github.com/grafana/authlib/claims"
	"google.golang.org/grpc"
)

// In this example, OriginContextKey is the key used to store the origin in the context.
type OriginContextKey struct{}

// idTokenExtractor is a helper function to get the user ID Token from context
func idTokenExtractor(ctx context.Context) (string, error) {
	authInfo, ok := claims.From(ctx)
	if !ok {
		return "", fmt.Errorf("no claims found")
	}

	extra := authInfo.GetExtra()
	if token, exists := extra["id-token"]; exists && len(token) != 0 && token[0] != "" {
		return token[0], nil
	}

	return "", fmt.Errorf("id-token not found")
}

// originExtractor is a helper function populate gRPC metadata with a custom Origin metadata
func originExtractor(ctx context.Context) (key string, values []string, err error) {
	origin, ok := ctx.Value(OriginContextKey{}).(string)
	if !ok {
		return "", nil, errors.New("Missing origin from context")
	}
	return "X-Origin", []string{origin}, nil
}

func main() {
	// The client interceptor authenticates requests to the gRPC server injecting
	// the ID token along with a custom origin metadata into the request metadata.
	// Since we explicitly disable it, the client interceptor won't add a service
	// access token to the request.
	clientInt, err := authnlib.NewGrpcClientInterceptor(
		&authnlib.GrpcClientConfig{},
		authnlib.WithDisableAccessTokenOption(),
		authnlib.WithIDTokenExtractorOption(idTokenExtractor),
		authnlib.WithMetadataExtractorOption(originExtractor),
	)
	if err != nil {
		os.Exit(1)
	}

	conn, err := grpc.NewClient(
		"myService:10000",
		grpc.WithUnaryInterceptor(clientInt.UnaryClientInterceptor),
		grpc.WithStreamInterceptor(clientInt.StreamClientInterceptor),
	)

	// ...
}

Server side:

import (
	authnlib "github.com/grafana/authlib/authn"
	"github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/auth"
	"google.golang.org/grpc"
)

func main() (*authnlib.GrpcAuthenticator, error) {
	// A grpc service
	service := MyService{}

	// This authenticator only verifies the ID token is present
	// and properly signed by the signing authority.
	authenticator := authnlib.NewGrpcAuthenticator(
		&authnlib.GrpcAuthenticatorConfig{
			KeyRetrieverConfig: authnlib.KeyRetrieverConfig{
				SigningKeysURL: "https://token-signer/v1/keys",
			},
			VerifierConfig: authnlib.VerifierConfig{},
		},
		authnlib.WithDisableAccessTokenAuthOption(),
		authnlib.WithIDTokenAuthOption(true),
	)

	// Create a new grpc server
	server = grpc.NewServer(
		grpc.ChainUnaryInterceptor(
			auth.UnaryServerInterceptor(authenticator.Authenticate),
			// TODO - Add origin handler
		),
		grpc.ChainStreamInterceptor(
			auth.StreamServerInterceptor(authenticator.Authenticate),
			// TODO - Add origin handler
		),
	)
	server.RegisterService(&authzv1.MyService_ServiceDesc, service)

	// ...
}

Documentation

Index

Constants

View Source
const (
	DefaultAccessTokenMetadataKey = "X-Access-Token"
	DefaultIdTokenMetadataKey     = "X-Id-Token"
)

Variables

View Source
var (
	ErrFetchingSigningKey = errors.New("unable to fetch signing keys")

	ErrParseToken        = fmt.Errorf("%w: failed to parse as jwt token", errInvalidToken)
	ErrInvalidTokenType  = fmt.Errorf("%w: invalid token type", errInvalidToken)
	ErrInvalidSigningKey = fmt.Errorf("%w: unrecognized signing key", errInvalidToken)

	ErrExpiredToken    = fmt.Errorf("%w: expired token", errInvalidToken)
	ErrInvalidAudience = fmt.Errorf("%w: invalid audience", errInvalidToken)

	ErrMissingConfig = errors.New("missing config")
)
View Source
var (
	ErrMissingNamespace = errors.New("missing required namespace")
	ErrMissingAudiences = errors.New("missing required audiences")

	ErrInvalidExchangeResponse = errors.New("invalid exchange response")
)
View Source
var (
	ErrorMissingMetadata    = status.Error(codes.Unauthenticated, "unauthenticated: no metadata found")
	ErrorMissingIDToken     = status.Error(codes.Unauthenticated, "unauthenticated: missing id token")
	ErrorMissingAccessToken = status.Error(codes.Unauthenticated, "unauthenticated: missing access token")
	ErrorInvalidIDToken     = status.Error(codes.PermissionDenied, "unauthorized: invalid id token")
	ErrorInvalidAccessToken = status.Error(codes.PermissionDenied, "unauthorized: invalid access token")
	ErrorNamespacesMismatch = status.Error(codes.PermissionDenied, "unauthorized: access and id token namespaces mismatch")
	ErrorInvalidSubject     = status.Error(codes.PermissionDenied, "unauthorized: invalid subject")
	ErrorInvalidSubjectType = status.Error(codes.PermissionDenied, "unauthorized: invalid subject type")
)

Functions

func AddCallerAuthInfoToContext deprecated

func AddCallerAuthInfoToContext(ctx context.Context, info CallerAuthInfo) context.Context

Deprecated: use claims.With(...)

func IsInvalidTokenErr

func IsInvalidTokenErr(err error) bool

Types

type Access

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

func NewAccessClaims

func NewAccessClaims(c Claims[AccessTokenClaims]) *Access

func (*Access) Audience

func (c *Access) Audience() []string

Audience implements claims.IdentityClaims.

func (*Access) DelegatedPermissions

func (c *Access) DelegatedPermissions() []string

DelegatedPermissions implements claims.AccessClaims.

func (*Access) Expiry

func (c *Access) Expiry() *time.Time

Expiry implements claims.IdentityClaims.

func (*Access) IsNil

func (c *Access) IsNil() bool

IsNil implements claims.AccessClaims.

func (*Access) IssuedAt

func (c *Access) IssuedAt() *time.Time

IssuedAt implements claims.IdentityClaims.

func (*Access) Issuer

func (c *Access) Issuer() string

Issuer implements claims.IdentityClaims.

func (*Access) JTI

func (c *Access) JTI() string

ID implements claims.IdentityClaims.

func (*Access) Namespace

func (c *Access) Namespace() string

Namespace implements claims.IdentityClaims.

func (*Access) NotBefore

func (c *Access) NotBefore() *time.Time

NotBefore implements claims.IdentityClaims.

func (*Access) Permissions

func (c *Access) Permissions() []string

Permissions implements claims.AccessClaims.

func (*Access) Scopes

func (c *Access) Scopes() []string

Scopes implements claims.AccessClaims.

func (*Access) Subject

func (c *Access) Subject() string

Subject implements claims.IdentityClaims.

type AccessTokenClaims

type AccessTokenClaims struct {
	// Namespace takes the form of '<type>-<id>', '*' means all namespaces.
	// Type can be either org or stack.
	Namespace string `json:"namespace"`
	// Access policy scopes
	Scopes []string `json:"scopes"`
	// Grafana roles
	Permissions []string `json:"permissions"`
	// On-behalf-of user
	DelegatedPermissions []string `json:"delegatedPermissions"`
}

type AccessTokenVerifier

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

AccessTokenVerifier is a convenient wrapper around `Verifier` used to verify and authenticate Grafana issued AccessTokens.

func NewAccessTokenVerifier

func NewAccessTokenVerifier(cfg VerifierConfig, keys KeyRetriever) *AccessTokenVerifier

func NewUnsafeAccessTokenVerifier

func NewUnsafeAccessTokenVerifier(cfg VerifierConfig) *AccessTokenVerifier

func (*AccessTokenVerifier) Verify

type AuthInfo

type AuthInfo struct {
	IdentityClaims *Identity
	AccessClaims   *Access
}

func (*AuthInfo) GetAccess

func (c *AuthInfo) GetAccess() claims.AccessClaims

Access implements claims.AuthInfo.

func (*AuthInfo) GetExtra

func (c *AuthInfo) GetExtra() map[string][]string

Extra implements claims.AuthInfo.

func (*AuthInfo) GetGroups

func (c *AuthInfo) GetGroups() []string

Groups implements claims.AuthInfo.

func (*AuthInfo) GetIdentity

func (c *AuthInfo) GetIdentity() claims.IdentityClaims

Identity implements claims.AuthInfo.

func (*AuthInfo) GetName

func (c *AuthInfo) GetName() string

Name implements claims.AuthInfo.

func (*AuthInfo) GetUID

func (c *AuthInfo) GetUID() string

UID implements claims.AuthInfo.

type CallerAuthInfo deprecated

type CallerAuthInfo struct {
	IDTokenClaims     *Claims[IDTokenClaims]
	AccessTokenClaims Claims[AccessTokenClaims]
}

Deprecated: Use authn.AuthInfo

func GetCallerAuthInfoFromContext deprecated

func GetCallerAuthInfoFromContext(ctx context.Context) (CallerAuthInfo, bool)

Deprecated: use claims.From(...)

func (*CallerAuthInfo) GetAccess

func (c *CallerAuthInfo) GetAccess() claims.AccessClaims

Access implements claims.AuthInfo.

func (*CallerAuthInfo) GetExtra

func (c *CallerAuthInfo) GetExtra() map[string][]string

GetExtra implements claims.AuthInfo.

func (*CallerAuthInfo) GetGroups

func (c *CallerAuthInfo) GetGroups() []string

GetGroups implements claims.AuthInfo.

func (*CallerAuthInfo) GetIdentity

func (c *CallerAuthInfo) GetIdentity() claims.IdentityClaims

Identity implements claims.AuthInfo.

func (*CallerAuthInfo) GetName

func (c *CallerAuthInfo) GetName() string

GetName implements claims.AuthInfo.

func (*CallerAuthInfo) GetUID

func (c *CallerAuthInfo) GetUID() string

GetUID implements claims.AuthInfo.

type CallerAuthInfoContextKey

type CallerAuthInfoContextKey struct{}

type Claims

type Claims[T any] struct {
	*jwt.Claims
	Rest T
	// contains filtered or unexported fields
}

type ContextMetadataExtractor

type ContextMetadataExtractor func(context.Context) (key string, values []string, err error)

type DefaultKeyRetriever

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

func (*DefaultKeyRetriever) Get

func (s *DefaultKeyRetriever) Get(ctx context.Context, keyID string) (*jose.JSONWebKey, error)

type DefaultKeyRetrieverOption

type DefaultKeyRetrieverOption func(*DefaultKeyRetriever)

func WithHTTPClientKeyRetrieverOpt

func WithHTTPClientKeyRetrieverOpt(client *http.Client) DefaultKeyRetrieverOption

WithHTTPClientKeyRetrieverOpt allows setting the HTTP client to be used by the key retriever.

type ExchangeClientOpts

type ExchangeClientOpts func(c *TokenExchangeClient)

ExchangeClientOpts allows setting custom parameters during construction.

func WithHTTPClient

func WithHTTPClient(client *http.Client) ExchangeClientOpts

WithHTTPClient allows setting the HTTP client to be used by the token exchange client.

type GrpcAuthenticator

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

GrpcAuthenticator is a gRPC authenticator that authenticates incoming requests based on the access token and ID token.

func NewGrpcAuthenticator

func NewGrpcAuthenticator(cfg *GrpcAuthenticatorConfig, opts ...GrpcAuthenticatorOption) (*GrpcAuthenticator, error)

NewGrpcAuthenticator creates a new gRPC authenticator that uses safe verifiers (i.e. JWT signature is checked). If a KeyRetriever is not provided via WithKeyRetrieverOption, a default one is created using the configuration provided via GrpcAuthenticatorConfig.KeyRetrieverConfig.

func NewUnsafeGrpcAuthenticator

func NewUnsafeGrpcAuthenticator(cfg *GrpcAuthenticatorConfig, opts ...GrpcAuthenticatorOption) *GrpcAuthenticator

NewUnsafeGrpcAuthenticator creates a new gRPC authenticator that uses unsafe verifiers (i.e. JWT signature is not checked). Unsafe verifiers do not perform key retrieval and JWT signtature validation. **Use with caution**.

func (*GrpcAuthenticator) Authenticate

func (ga *GrpcAuthenticator) Authenticate(ctx context.Context) (context.Context, error)

Authenticate authenticates the incoming request based on the access token and ID token, and returns the context with the caller information.

type GrpcAuthenticatorConfig

type GrpcAuthenticatorConfig struct {
	// AccessTokenMetadataKey is the key used to retrieve the access token from the incoming metadata.
	// Defaults to "X-Access-Token".
	AccessTokenMetadataKey string
	// IDTokenMetadataKey is the key used to retrieve the ID token from the incoming metadata.
	// Defaults to "X-Id-Token".
	IDTokenMetadataKey string

	// KeyRetrieverConfig holds the configuration for the key retriever.
	// Ignored if KeyRetrieverOption is provided or when unsafe verifiers are used via NewUnsafeGrpcAuthenticator.
	KeyRetrieverConfig KeyRetrieverConfig
	// VerifierConfig holds the configuration for the token verifiers.
	VerifierConfig VerifierConfig
	// contains filtered or unexported fields
}

GrpcAuthenticatorConfig holds the configuration for the gRPC authenticator.

type GrpcAuthenticatorOption

type GrpcAuthenticatorOption func(*GrpcAuthenticator)

GrpcAuthenticatorOptions

func WithDisableAccessTokenAuthOption

func WithDisableAccessTokenAuthOption() GrpcAuthenticatorOption

WithDisableAccessTokenAuthOption is an option to disable access token authentication. Warning: Using this option means there won't be any service authentication.

func WithIDTokenAuthOption

func WithIDTokenAuthOption(required bool) GrpcAuthenticatorOption

WithIDTokenAuthOption is a flag to enable ID token authentication. If required is true, the ID token is required for authentication.

func WithKeyRetrieverOption

func WithKeyRetrieverOption(kr KeyRetriever) GrpcAuthenticatorOption

func WithTracerAuthOption

func WithTracerAuthOption(tracer trace.Tracer) GrpcAuthenticatorOption

WithTracerAuthOption sets the tracer for the gRPC authenticator.

type GrpcClientConfig

type GrpcClientConfig struct {
	// AccessTokenMetadataKey is the key used to store the access token in the outgoing context metadata.
	// Defaults to "X-Access-Token".
	AccessTokenMetadataKey string
	// IDTokenMetadataKey is the key used to store the ID token in the outgoing context metadata.
	// Not required if IDTokenExtractor is provided. Defaults to "X-Id-Token".
	IDTokenMetadataKey string
	// TokenClientConfig holds the configuration for the token exchange client.
	// Not required if TokenClient is provided.
	TokenClientConfig *TokenExchangeConfig
	// TokenRequest is the token request to be used for token exchange.
	// This assumes the token request is static and does not change.
	TokenRequest *TokenExchangeRequest
	// contains filtered or unexported fields
}

GrpcClientConfig holds the configuration for the gRPC client interceptor.

type GrpcClientInterceptor

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

GrpcClientInterceptor is a gRPC client interceptor that adds an access token to the outgoing context metadata.

func (*GrpcClientInterceptor) StreamClientInterceptor

func (gci *GrpcClientInterceptor) StreamClientInterceptor(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, streamer grpc.Streamer, opts ...grpc.CallOption) (grpc.ClientStream, error)

func (*GrpcClientInterceptor) UnaryClientInterceptor

func (gci *GrpcClientInterceptor) UnaryClientInterceptor(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error

type GrpcClientInterceptorOption

type GrpcClientInterceptorOption func(*GrpcClientInterceptor)

func WithDisableAccessTokenOption

func WithDisableAccessTokenOption() GrpcClientInterceptorOption

WithDisableAccessTokenOption is an option to disable access token authentication. Warning: Using this option means there won't be any service authentication.

func WithIDTokenExtractorOption

func WithIDTokenExtractorOption(extractor func(context.Context) (string, error)) GrpcClientInterceptorOption

func WithMetadataExtractorOption

func WithMetadataExtractorOption(extractors ...ContextMetadataExtractor) GrpcClientInterceptorOption

func WithTokenClientOption

func WithTokenClientOption(tokenClient TokenExchanger) GrpcClientInterceptorOption

func WithTracerOption

func WithTracerOption(tracer trace.Tracer) GrpcClientInterceptorOption

WithTracerOption sets the tracer for the gRPC authenticator.

type IDTokenClaims

type IDTokenClaims struct {
	// Identifier is the unique ID of the of entity
	Identifier string `json:"identifier"`
	// The type of the entity.
	Type claims.IdentityType `json:"type"`
	// Namespace takes the form of '<type>-<id>', '*' means all namespaces.
	// Type can be either org or stack.
	Namespace string `json:"namespace"`
	// AuthenticatedBy is the method used to authenticate the identity.
	AuthenticatedBy string `json:"authenticatedBy,omitempty"`
	Email           string `json:"email,omitempty"`
	EmailVerified   bool   `json:"email_verified,omitempty"`
	// Username of the user (login attribute on the Identity)
	Username string `json:"username,omitempty"`
	// Display name of the user (name attribute if it is set, otherwise the login or email)
	DisplayName string `json:"name,omitempty"`
}

type IDTokenVerifier

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

IDTokenVerifier is a convenient wrapper around `Verifier` used to verify grafana issued id tokens.

func NewIDTokenVerifier

func NewIDTokenVerifier(cfg VerifierConfig, keys KeyRetriever) *IDTokenVerifier

func NewUnsafeIDTokenVerifier

func NewUnsafeIDTokenVerifier(cfg VerifierConfig) *IDTokenVerifier

func (*IDTokenVerifier) Verify

func (e *IDTokenVerifier) Verify(ctx context.Context, token string) (*Claims[IDTokenClaims], error)

type Identity

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

func NewIdentityClaims

func NewIdentityClaims(c Claims[IDTokenClaims]) *Identity

func (*Identity) Audience

func (c *Identity) Audience() []string

Audience implements claims.IdentityClaims.

func (*Identity) AuthenticatedBy

func (c *Identity) AuthenticatedBy() string

AuthenticatedBy implements claims.IdentityClaims.

func (*Identity) DisplayName

func (c *Identity) DisplayName() string

DisplayName implements claims.IdentityClaims.

func (*Identity) Email

func (c *Identity) Email() string

Email implements claims.IdentityClaims.

func (*Identity) EmailVerified

func (c *Identity) EmailVerified() bool

EmailVerified implements claims.IdentityClaims.

func (*Identity) Expiry

func (c *Identity) Expiry() *time.Time

Expiry implements claims.IdentityClaims.

func (*Identity) Identifier

func (c *Identity) Identifier() string

Identifier implements claims.IdentityClaims.

func (*Identity) IdentityType

func (c *Identity) IdentityType() claims.IdentityType

UID implements claims.IdentityClaims.

func (*Identity) IsNil

func (c *Identity) IsNil() bool

IsNil implements claims.IdentityClaims.

func (*Identity) IssuedAt

func (c *Identity) IssuedAt() *time.Time

IssuedAt implements claims.IdentityClaims.

func (*Identity) Issuer

func (c *Identity) Issuer() string

Issuer implements claims.IdentityClaims.

func (*Identity) JTI

func (c *Identity) JTI() string

ID implements claims.IdentityClaims.

func (*Identity) Namespace

func (c *Identity) Namespace() string

Namespace implements claims.IdentityClaims.

func (*Identity) NotBefore

func (c *Identity) NotBefore() *time.Time

NotBefore implements claims.IdentityClaims.

func (*Identity) Subject

func (c *Identity) Subject() string

Subject implements claims.IdentityClaims.

func (*Identity) Username

func (c *Identity) Username() string

Username implements claims.IdentityClaims.

type KeyRetriever

type KeyRetriever interface {
	Get(ctx context.Context, keyID string) (*jose.JSONWebKey, error)
}

type KeyRetrieverConfig

type KeyRetrieverConfig struct {
	SigningKeysURL string `yaml:"signingKeysUrl"`
}

func (*KeyRetrieverConfig) RegisterFlags

func (c *KeyRetrieverConfig) RegisterFlags(prefix string, fs *flag.FlagSet)

type NoopVerifier

type NoopVerifier[T any] struct{}

func NewNoopVerifier

func NewNoopVerifier[T any]() *NoopVerifier[T]

func (*NoopVerifier[T]) Verify

func (v *NoopVerifier[T]) Verify(ctx context.Context, token string) (*Claims[T], error)

type TokenExchangeClient

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

func NewTokenExchangeClient

func NewTokenExchangeClient(cfg TokenExchangeConfig, opts ...ExchangeClientOpts) (*TokenExchangeClient, error)

func (*TokenExchangeClient) Exchange

type TokenExchangeConfig

type TokenExchangeConfig struct {
	// Token used to perform the exchange request.
	Token string `yaml:"token"`
	// Url called to perform exchange request.
	TokenExchangeURL string `yaml:"tokenExchangeUrl"`
}

func (*TokenExchangeConfig) RegisterFlags

func (c *TokenExchangeConfig) RegisterFlags(prefix string, fs *flag.FlagSet)

type TokenExchangeRequest

type TokenExchangeRequest struct {
	// Namespace token should be signed with.
	// Use wildcard '*' to create a token for all namespaces.
	Namespace string `json:"namespace"`
	// Audiences token should be signed with.
	Audiences []string `json:"audiences"`
}

type TokenExchangeResponse

type TokenExchangeResponse struct {
	Token string
}

type TokenExchanger

type TokenExchanger interface {
	Exchange(ctx context.Context, r TokenExchangeRequest) (*TokenExchangeResponse, error)
}

Provided for mockability of client

type TokenType

type TokenType = string
const (
	TokenTypeID     TokenType = "jwt"
	TokenTypeAccess TokenType = "at+jwt"
)

type UnsafeVerifierBase

type UnsafeVerifierBase[T any] struct {
	// contains filtered or unexported fields
}

func NewUnsafeVerifier

func NewUnsafeVerifier[T any](cfg VerifierConfig, typ TokenType) *UnsafeVerifierBase[T]

func (*UnsafeVerifierBase[T]) Verify

func (v *UnsafeVerifierBase[T]) Verify(ctx context.Context, token string) (*Claims[T], error)

Verify will parse and verify provided token, if `AllowedAudiences` was configured those will be validated as well.

type Verifier

type Verifier[T any] interface {
	// Verify will parse and verify provided token, if `AllowedAudiences` was configured those will be validated as well.
	Verify(ctx context.Context, token string) (*Claims[T], error)
}

type VerifierBase

type VerifierBase[T any] struct {
	// contains filtered or unexported fields
}

func NewVerifier

func NewVerifier[T any](cfg VerifierConfig, typ TokenType, keys KeyRetriever) *VerifierBase[T]

func (*VerifierBase[T]) Verify

func (v *VerifierBase[T]) Verify(ctx context.Context, token string) (*Claims[T], error)

Verify will parse and verify provided token, if `AllowedAudiences` was configured those will be validated as well.

type VerifierConfig

type VerifierConfig struct {
	AllowedAudiences jwt.Audience `yaml:"allowedAudiences"`
}

func (*VerifierConfig) RegisterFlags

func (c *VerifierConfig) RegisterFlags(prefix string, fs *flag.FlagSet)

Jump to

Keyboard shortcuts

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