auth

package
v5.5.0 Latest Latest
Warning

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

Go to latest
Published: Dec 1, 2024 License: MIT Imports: 20 Imported by: 4

Documentation

Index

Constants

View Source
const (
	// JWTServiceName identifier for the `JWTService`.
	JWTServiceName = "goyave.jwt"
)
View Source
const MetaAuth = "goyave.require-auth"

MetaAuth the authentication middleware will only authenticate the user if this meta is present in the matched route or any of its parent and is equal to `true`.

Variables

This section is empty.

Functions

This section is empty.

Types

type Authenticator

type Authenticator[T any] interface {
	goyave.Composable

	// Authenticate fetch the user corresponding to the credentials
	// found in the given request and returns it.
	// If no user can be authenticated, returns the error detailing why the
	// authentication failed. The error message is already localized.
	//
	// The error returned doesn't need to be wrapped as it will only
	// be used for the message returned in the response.
	//
	// If an unexpected error happens (e.g.: database error), this
	// method should panic instead of returning an error.
	Authenticate(request *goyave.Request) (*T, error)
}

Authenticator is an object in charge of authenticating a client.

The generic type should be a DTO and not be a pointer. The `request.User` will use this type on successful authentication.

type BasicAuthenticator

type BasicAuthenticator[T any] struct {
	goyave.Component

	UserService UserService[T]

	// PasswordField the name of T's struct field that holds the user's hashed password.
	// It will be used to compare the password hash with the user input.
	PasswordField string

	// Optional defines if the authenticator allows requests that
	// don't provide credentials. Handlers should therefore check
	// if `request.User` is not `nil` before accessing it.
	Optional bool
}

BasicAuthenticator implementation of Authenticator with the Basic authentication method.

The T parameter represents the user DTO and should not be a pointer. The DTO used should be different from the DTO returned to clients as a response because it needs to contain the user's password.

func NewBasicAuthenticator

func NewBasicAuthenticator[T any](userService UserService[T], passwordField string) *BasicAuthenticator[T]

NewBasicAuthenticator create a new authenticator for the Basic authentication flow.

The T parameter represents the user DTO and should not be a pointer. The DTO used should be different from the DTO returned to clients as a response because it needs to contain the user's password.

The `passwordField` corresponds to the name of T's struct field that holds the user's hashed password. It will be used to compare the password hash with the user input.

func (*BasicAuthenticator[T]) Authenticate

func (a *BasicAuthenticator[T]) Authenticate(request *goyave.Request) (*T, error)

Authenticate fetch the user corresponding to the credentials found in the given request and returns it. If no user can be authenticated, returns an error. The password is checked using bcrypt.

type BasicUser

type BasicUser struct {
	Name string
}

BasicUser a simple user for config-based basic authentication.

type ConfigBasicAuthenticator

type ConfigBasicAuthenticator struct {
	goyave.Component
}

ConfigBasicAuthenticator implementation of Authenticator with the Basic authentication method, using username and password from the configuration.

func (*ConfigBasicAuthenticator) Authenticate

func (a *ConfigBasicAuthenticator) Authenticate(request *goyave.Request) (*BasicUser, error)

Authenticate check if the request basic auth header matches the "auth.basic.username" and "auth.basic.password" config entries.

type ExtraJWTClaims

type ExtraJWTClaims struct{}

ExtraJWTClaims when using the built-in `JWTAuthenticator`, this key can be used to retrieve the JWT claims in the request's `Extra`.

type Handler

type Handler[T any] struct {
	Authenticator[T]
}

Handler a middleware that automatically sets the request's `User` if the authenticator succeeds.

Supports the `auth.Unauthorizer` interface.

The T parameter represents the user DTO and should not be a pointer.

func ConfigBasicAuth

func ConfigBasicAuth() *Handler[BasicUser]

ConfigBasicAuth create a new authenticator middleware for config-based Basic authentication. On auth success, the request user is set to a `*BasicUser`. The user is authenticated if the "auth.basic.username" and "auth.basic.password" config entries match the request's Authorization header.

func Middleware

func Middleware[T any](authenticator Authenticator[T]) *Handler[T]

Middleware returns an authentication middleware which will use the given authenticator and set the request's `User` according to the generic type `T`, which should be a DTO.

This middleware should be used as a global middleware, and all routes (ou routers) that require authentication should have the meta `MetaAuth` set to `true`. If the matched route or any of its parent doesn't have this meta or if it's not equal to `true`, the authentication is skipped.

func (*Handler[T]) Handle

func (m *Handler[T]) Handle(next goyave.Handler) goyave.Handler

Handle set the request's `User` to the user returned by the authenticator if it succeeds. Blocks if the authentication is not successful. If the authenticator implements `Unauthorizer`, `OnUnauthorized` is called, otherwise returns a default `401 Unauthorized` error. If the matched route doesn't contain the `MetaAuth` or if it's not equal to `true`, the middleware is skipped.

type JWTAuthenticator

type JWTAuthenticator[T any] struct {
	goyave.Component

	UserService UserService[T]

	// SigningMethod expected by this authenticator when parsing JWT.
	// Defaults to HMAC.
	SigningMethod jwt.SigningMethod

	// ClaimName the name of the claim used to retrieve the user.
	// Defaults to "sub".
	ClaimName string

	// Optional defines if the authenticator allows requests that
	// don't provide credentials. Handlers should therefore check
	// if `request.User` is not `nil` before accessing it.
	Optional bool
	// contains filtered or unexported fields
}

JWTAuthenticator implementation of Authenticator using a JSON Web Token.

The T parameter represents the user DTO and should not be a pointer.

func NewJWTAuthenticator

func NewJWTAuthenticator[T any](userService UserService[T]) *JWTAuthenticator[T]

NewJWTAuthenticator create a new authenticator for the JSON Web Token authentication flow.

The T parameter represents the user DTO and should not be a pointer.

func (*JWTAuthenticator[T]) Authenticate

func (a *JWTAuthenticator[T]) Authenticate(request *goyave.Request) (*T, error)

Authenticate fetch the user corresponding to the token found in the given request and returns it. If no user can be authenticated, returns an error.

If the token is valid and has claims, those claims will be added to `request.Extra` with the key "jwt_claims".

func (*JWTAuthenticator[T]) Init

func (a *JWTAuthenticator[T]) Init(server *goyave.Server)

Init the authenticator. Automatically registers the `JWTService` if not already registered, using `osfs.FS` as file system for the keys.

type JWTController

type JWTController[T any] struct {
	goyave.Component

	UserService UserService[T]

	// SigningMethod used to generate the token using the default
	// TokenFunc. By default, uses `jwt.SigningMethodHS256`.
	SigningMethod jwt.SigningMethod

	// The function generating the token on a successful authentication.
	// Defaults to a JWT signed with HS256 and containing the username as the
	// "sub" claim.
	TokenFunc TokenFunc[T]

	// UsernameRequestField the name of the request's body field
	// used as username in the authentication process.
	// Defaults to "username"
	UsernameRequestField string
	// PasswordRequestField the name of the request's body field
	// used as password in the authentication process.
	// Defaults to "password"
	PasswordRequestField string
	// PasswordField the name of T's struct field that holds the user's hashed password.
	// It will be used to compare the password hash with the user input.
	PasswordField string
	// contains filtered or unexported fields
}

JWTController controller adding a login route returning a JWT for quick prototyping.

The T parameter represents the user DTO and should not be a pointer. The DTO used should be different from the DTO returned to clients as a response because it needs to contain the user's password.

func NewJWTController

func NewJWTController[T any](userService UserService[T], passwordField string) *JWTController[T]

NewJWTController create a new JWTController that registers a login route returning a JWT for quick prototyping.

The `passwordField` corresponds to the name of T's struct field that holds the user's hashed password. It will be used to compare the password hash with the user input.

func (*JWTController[T]) Init

func (c *JWTController[T]) Init(server *goyave.Server)

Init the controller. Automatically registers the `JWTService` if not already registered, using `osfs.FS` as file system for the signing keys.

func (*JWTController[T]) Login

func (c *JWTController[T]) Login(response *goyave.Response, request *goyave.Request)

Login POST handler for token-based authentication. Creates a new token for the user authenticated with the body fields defined in the controller and returns it as a response. The password is checked using bcrypt.

func (*JWTController[T]) RegisterRoutes

func (c *JWTController[T]) RegisterRoutes(router *goyave.Router)

RegisterRoutes register the "/login" route (with validation) on the given router.

type JWTService

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

JWTService providing signature keys cache and JWT generation.

This service is identified by `auth.JWTServiceName`.

func NewJWTService

func NewJWTService(config *config.Config, fs fs.FS) *JWTService

NewJWTService create a new `JWTService` with the given config and file system. The file system is used to get the signing keys.

func (*JWTService) GenerateToken

func (s *JWTService) GenerateToken(username any) (string, error)

GenerateToken generate a new JWT. The token is created using the HMAC SHA256 method and signed using the `auth.jwt.secret` config entry. The token is set to expire in the amount of seconds defined by the `auth.jwt.expiry` config entry.

The generated token will contain the following claims:

  • `sub`: has the value of the `id` parameter
  • `nbf`: "Not before", the current timestamp is used
  • `exp`: "Expiry", the current timestamp plus the `auth.jwt.expiry` config entry.

func (*JWTService) GenerateTokenWithClaims

func (s *JWTService) GenerateTokenWithClaims(claims jwt.MapClaims, signingMethod jwt.SigningMethod) (string, error)

GenerateTokenWithClaims generates a new JWT with custom claims. The token is set to expire in the amount of seconds defined by the `auth.jwt.expiry` config entry. Depending on the given signing method, the following configuration entries will be used:

  • RSA: `auth.jwt.rsa.private`: path to the private PEM-encoded RSA key.
  • ECDSA: `auth.jwt.ecdsa.private`: path to the private PEM-encoded ECDSA key.
  • HMAC: `auth.jwt.secret`: HMAC secret

The generated token will also contain the following claims:

  • `nbf`: "Not before", the current timestamp is used
  • `exp`: "Expiry", the current timestamp plus the `auth.jwt.expiry` config entry.

`nbf` and `exp` can be overridden if they are set in the `claims` parameter.

func (*JWTService) GetKey

func (s *JWTService) GetKey(entry string) (any, error)

GetKey load a JWT signature key from the config. List of `entry` parameter possible values:

  • `auth.jwt.rsa.public`
  • `auth.jwt.rsa.private`
  • `auth.jwt.ecdsa.public`
  • `auth.jwt.ecdsa.private`
  • `auth.jwt.secret`

To optimize subsequent requests and avoid IO for keys that are stored on the disk, the keys are cached.

func (*JWTService) GetPrivateKey

func (s *JWTService) GetPrivateKey(signingMethod jwt.SigningMethod) (any, error)

GetPrivateKey loads the private key that corresponds to the given `signingMethod`.

func (*JWTService) Name

func (s *JWTService) Name() string

Name returns the name of the service.

type TokenFunc

type TokenFunc[T any] func(request *goyave.Request, user *T) (string, error)

TokenFunc is the function used by JWTController to generate tokens during login process.

type Unauthorizer

type Unauthorizer interface {
	OnUnauthorized(response *goyave.Response, request *goyave.Request, err error)
}

Unauthorizer can be implemented by Authenticators to define custom behavior when authentication fails.

type UserService

type UserService[T any] interface {
	FindByUsername(ctx context.Context, username any) (*T, error)
}

UserService is the dependency of authenticators used to retrieve a user by its "username".

A username is actually any identifier (an ID, a email, a name, etc). It is the responsibility of the service implementation to check the type of the "username" and either convert it or return an error simulating a non-existing record (`gorm.ErrRecordNotFound`).

If the record could not be found, the error returned should be of type `gorm.ErrRecordNotFound`.

Jump to

Keyboard shortcuts

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