oauth2as

package
v0.0.0-...-f15f685 Latest Latest
Warning

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

Go to latest
Published: Sep 14, 2025 License: BSD-3-Clause Imports: 21 Imported by: 0

README

oauth2as

Go Reference

Go library for implementing Oauth2/OIDC OPs (Servers). In active development

Example

Start the server

go run ./cmd/oidc-example-op

Request some tokens


Documentation

Overview

Package oauth2as is an library implementation of helpers for implementing the core OIDC specification (https://openid.net/specs/openid-connect-core-1_0.html). It aims to provide the tools needed to build a compliant implementation of the specification. Note: It does not _enforce_ all behaviours required by the spec, implementations that consume this should be sure to not introduce non-compliant behaviours.

Index

Constants

View Source
const (
	// DefaultAuthValidityTime is used if the AuthValidityTime is not
	// configured.
	DefaultAuthValidityTime = 10 * time.Minute
	// DefaultCodeValidityTime is used if the CodeValidityTime is not
	// configured.
	DefaultCodeValidityTime = 60 * time.Second
	// DefaultIDTokenValidity is the default IDTokenValidity time.
	DefaultIDTokenValidity = 1 * time.Hour
	// DefaultsAccessTokenValidity is the default AccessTokenValdity time.
	DefaultsAccessTokenValidity = 1 * time.Hour
	// DefaultMaxRefreshTime is the default value sessions are refreshable for.
	DefaultMaxRefreshTime = 30 * 24 * time.Hour
)

Variables

This section is empty.

Functions

This section is empty.

Types

type AlgorithmSigner

type AlgorithmSigner interface {
	// PublicKeyset is used to verify issued tokens, i.e in the Userinfo
	// endpoint.
	jwt.PublicKeyset
	// SignWithAlgorithm should sign the payload with the given algorithm and
	// type header, and return the compact representation of the signed token.
	SignWithAlgorithm(ctx context.Context, alg, typHdr string, payload []byte) (string, error)
	// SupportedAlgorithms returns the list of JWT algorithms supported by this
	// signer.
	SupportedAlgorithms() []string
}

type AuthGrant

type AuthGrant struct {
	// Request is the corresponding authorization request that we are granting
	// access for.
	Request *AuthRequest
	// GrantedScopes are the scopes that were actually granted.
	GrantedScopes []string
	// UserID is the user ID that was granted access. This is used to form the subject
	// claim, and is provided on subsequent actions.
	UserID string
	// Metadata is arbitraty metadata that can be stored with the grant. Can be
	// used for auditing or tracking other information that is associated with
	// the grant. This is not sensitive, and can be accessed at any time.
	Metadata map[string]string
	// EncryptedMetadata is the encrypted metadata that can be stored with the
	// grant. This is only available to token callbacks. Can be used to store
	// sensitive, grant-specific information like upstream auth tokens.
	EncryptedMetadata map[string]string
}

type AuthRequest

type AuthRequest struct {
	// ClientID is the client ID that is requesting authentication.
	ClientID string
	// RedirectURI the client specified. This is an OPTIONAL field, if not
	// passed will be set to the zero value. If provided, it will have been
	// validated.
	RedirectURI string
	// State is the state value that was passed in the request.
	State string
	// Scopes is the list of scopes that the client is requesting.
	Scopes []string
	// CodeChallenge is the PKCE code challenge. If it is provided, it will be
	// S256 format. If not provided, it will be an empty string.
	CodeChallenge string
	// ACRValues is the list of ACR values that the client is requesting.
	ACRValues []string

	// Raw is the raw URL values that were passed in the request.
	Raw url.Values
}

type ClientOpt

type ClientOpt func(opts *clientOpts)

ClientOpt is a flag that can be set on a given client, to adjust various behaviours.

func ClientOptSigningAlg

func ClientOptSigningAlg(alg jwt.SigningAlg) ClientOpt

func ClientOptSkipPKCE

func ClientOptSkipPKCE() ClientOpt

ClientOptSkipPKCE indicates that the client is not required to use PKCE

type ClientSource

type ClientSource interface {
	// IsValidClientID should return true if the passed client ID is valid
	IsValidClientID(_ context.Context, clientID string) (ok bool, err error)
	// ValidateClientSecret should confirm if the passed secret is valid for the
	// given client. If no secret is provided, clientSecret will be empty but
	// this will still be called.
	ValidateClientSecret(_ context.Context, clientID, clientSecret string) (ok bool, err error)
	// ValidateRedirectURI should return the list of valid redirect URIs. They
	// will be compared for an exact match, with the exception of loopback
	// addresses, which can have a variable port
	// (https://www.rfc-editor.org/rfc/rfc8252#section-7.3).
	RedirectURIs(_ context.Context, clientID string) ([]string, error)
	// ClientOpts returns the list of options for this client. See ClientOpt.
	ClientOpts(_ context.Context, clientID string) ([]ClientOpt, error)
}

ClientSource is used for validating client informantion for the general flow

type Config

type Config struct {
	// Issuer is the issuer we are serving for.
	Issuer string
	// Storage is the storage backend to use for the server.
	Storage Storage
	Clients ClientSource
	Signer  AlgorithmSigner

	Logger *slog.Logger

	TokenHandler    TokenHandler
	UserinfoHandler UserinfoHandler

	// AuthValidityTime is the maximum time an authorization flow/AuthID is
	// valid. This is the time from Starting to Finishing the authorization. The
	// optimal time here will be application specific, and should encompass how
	// long the app expects a user to complete the "upstream" authorization
	// process. Defaults to DefaultAuthValidityTime
	AuthValidityTime time.Duration
	// CodeValidityTime is the maximum time the authorization code is valid,
	// before it is exchanged for a token (code flow). This should be a short
	// value, as the exhange should generally not take long. Defaults to DefaultCodeValidityTime.
	CodeValidityTime time.Duration
	// IDTokenValidity sets the default validity for issued ID tokens. This can
	// be overridden on a per-request basis.
	IDTokenValidity time.Duration
	// AccessTokenValidity sets the default validity for issued access tokens.
	// This can be overridden on a per-request basis. Must be equal or less to
	// the IDTokenValitity time.
	AccessTokenValidity time.Duration
	// MaxRefreshTime sets the longest time a session can be refreshed for, from
	// the time it was created. This can be overridden on a per-request basis.
	// Defaults to DefaultMaxRefreshTime. Any refesh token may be considered
	// valid up until this time.
	MaxRefreshTime time.Duration
}

Config is used to set the configuration for creating a server instance.

type MemStorage

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

MemStorage implements the Storage interface with an in-memory dataset. All items return nil when not found.

func NewMemStorage

func NewMemStorage() *MemStorage

NewMemStorage creates a new in-memory storage instance.

func (*MemStorage) CreateGrant

func (m *MemStorage) CreateGrant(ctx context.Context, grant *StoredGrant) error

CreateGrant stores a new grant in memory.

func (*MemStorage) ExpireGrant

func (m *MemStorage) ExpireGrant(ctx context.Context, id uuid.UUID) error

ExpireGrant removes a grant from memory.

func (*MemStorage) GetGrant

func (m *MemStorage) GetGrant(ctx context.Context, id uuid.UUID) (*StoredGrant, error)

GetGrant retrieves a grant by its ID. Returns nil if not found.

func (*MemStorage) GetGrantByAuthCode

func (m *MemStorage) GetGrantByAuthCode(ctx context.Context, authCode []byte) (*StoredGrant, error)

GetGrantByAuthCode retrieves a grant by its authorization code. Returns nil if not found.

func (*MemStorage) GetGrantByRefreshToken

func (m *MemStorage) GetGrantByRefreshToken(ctx context.Context, refreshToken []byte) (*StoredGrant, error)

GetGrantByRefreshToken retrieves a grant by its refresh token. Returns nil if not found.

func (*MemStorage) UpdateGrant

func (m *MemStorage) UpdateGrant(ctx context.Context, grant *StoredGrant) error

UpdateGrant updates an existing grant in memory.

type Server

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

func NewServer

func NewServer(c Config) (*Server, error)

func (*Server) GrantAuth

func (s *Server) GrantAuth(ctx context.Context, grant *AuthGrant) (redirectURI string, _ error)

func (*Server) ParseAuthRequest

func (s *Server) ParseAuthRequest(req *http.Request) (*AuthRequest, error)

func (*Server) TokenHandler

func (s *Server) TokenHandler(w http.ResponseWriter, req *http.Request)

TokenHandler is used to handle the access token endpoint for code flow requests. This can handle both the initial access token request, as well as subsequent calls for refreshes.

If a handler returns an error, it will be checked and the endpoint will respond to the user appropriately. The session will not be invalidated automatically, it it the responsibility of the handler to delete if it requires this. * If the error implements an `Unauthorized() bool` method and the result of calling this is true, the caller will be notified of an `invalid_grant`. The error text will be returned as the `error_description` * All other errors will result an an InternalServerError

This will always return a response to the user, regardless of success or failure. As such, once returned the called can assume the HTTP request has been dealt with appropriately

https://openid.net/specs/openid-connect-core-1_0.html#TokenEndpoint https://openid.net/specs/openid-connect-core-1_0.html#RefreshTokens

func (*Server) UserinfoHandler

func (s *Server) UserinfoHandler(w http.ResponseWriter, req *http.Request)

UserinfoHandler can handle a request to the userinfo endpoint. If the request is not valid, an error will be returned. Otherwise handler will be invoked with information about the requestor passed in. This handler should write the appropriate response data in JSON format to the passed writer.

https://openid.net/specs/openid-connect-core-1_0.html#UserInfoResponse

type Storage

type Storage interface {
	// CreateGrant creates a new grant.
	CreateGrant(ctx context.Context, grant *StoredGrant) error
	// UpdateGrant updates an existing grant.
	UpdateGrant(ctx context.Context, grant *StoredGrant) error
	// ExpireGrant expires a grant.
	ExpireGrant(ctx context.Context, id uuid.UUID) error
	// GetGrant retrieves a grant by ID. If no grant is found, it should return
	// a nil grant.
	GetGrant(ctx context.Context, id uuid.UUID) (*StoredGrant, error)
	// GetGrantByAuthCode retrieves a grant by authorization code. If no grant
	// is found, it should return a nil grant. The code is a raw byte slice.
	GetGrantByAuthCode(ctx context.Context, authCode []byte) (*StoredGrant, error)
	// GetGrantByRefreshToken retrieves a grant by refresh token. If no grant
	// is found, it should return a nil grant. The token is a raw byte slice.
	GetGrantByRefreshToken(ctx context.Context, refreshToken []byte) (*StoredGrant, error)
}

Storage is the interface for storing and retrieving grants.

type StoredGrant

type StoredGrant struct {
	// ID is the unique identifier for this grant.
	ID uuid.UUID
	// AuthCode is the authorization code for the initial token exchange.
	AuthCode []byte
	// UserID is the user ID that was granted access.
	UserID string
	// ClientID is the client ID that was granted access.
	ClientID string
	// GrantedScopes are the scopes that were actually granted.
	GrantedScopes []string
	// Request captures the request that was used to grant access. Used for
	// finalizing the code flow.
	Request *AuthRequest
	// RefreshToken is the refresh token for the grant.
	RefreshToken []byte
	// GrantedAt is the time at which the grant was granted.
	GrantedAt time.Time
	// ExpiresAt is the time at which the grant will expire.
	ExpiresAt time.Time

	// Metadata is arbitrary metadata that can be stored with the grant.
	Metadata map[string]string
	// EncryptedMetadata stores the encrypted metadata associated with this
	// grant.
	EncryptedMetadata []byte
}

type TokenHandler

type TokenHandler func(_ context.Context, req *TokenRequest) (*TokenResponse, error)

type TokenRequest

type TokenRequest struct {
	// GrantID is the ID of the grant that was used to obtain the token.
	GrantID uuid.UUID
	// UserID is the user ID that was granted access.
	UserID string
	// ClientID is the client ID that was used to obtain the token.
	ClientID string
	// GrantedScopes are the scopes that were granted.
	GrantedScopes []string
	// Metadata is the metadata that was associated with the grant.
	Metadata map[string]string
	// EncryptedMetadata is the decrypted metadata that was associated with the
	// grant.
	EncryptedMetadata map[string]string

	// IsRefresh indicates if this is a refresh token request.
	IsRefresh bool
}

TokenRequest encapsulates the information from the initial request to the token endpoint. This is passed to the handler, to generate an appropriate response.

type TokenResponse

type TokenResponse struct {

	// may be zero, if so defaulted
	IDTokenExpiry     time.Time
	AccessTokenExpiry time.Time

	// IDClaims are the claims that will be included in the ID token. These will
	// be serialized to JSON, and then returned in the token. This is optional.
	// The following claims will always be overridden:
	// - iss
	// - iat
	// - auth_time
	// - nonce
	// The following claims will be defaulted if not set:
	// - sub
	// - exp
	// - aud
	IDClaims any
	// AccessTokenClaims is the claims that will be included in the access token.
	// The claims will be serialized to JSON, and then returned in the token.
	// The following claims will always be overridden:
	// - iss
	// - client_id
	// - iat
	// - jti
	// The following claims will be defaulted if not set:
	// - sub
	// - exp
	// - aud
	AccessTokenClaims any

	// RefreshTokenValidUntil indicates how long the returned refresh token should
	// be valid for, if one is issued. If zero, the default will be used.
	RefreshTokenValidUntil time.Time

	// Metadata is the metadata that was associated with the grant. If nil, the
	// existing metadata will be re-used.
	Metadata map[string]string
	// EncryptedMetadata is the encrypted metadata that was associated with the
	// grant. If nil, the existing encrypted metadata will be re-used.
	EncryptedMetadata map[string]string
}

TokenResponse is returned by the token endpoint handler, indicating what it should actually return to the user.

type UserinfoHandler

type UserinfoHandler func(ctx context.Context, uireq *UserinfoRequest) (*UserinfoResponse, error)

type UserinfoRequest

type UserinfoRequest struct {
	// Subject is the sub of the user this request is for.
	Subject string
}

UserinfoRequest contains information about this request to the UserInfo endpoint

type UserinfoResponse

type UserinfoResponse struct {
	// Subject is the sub of the user this request is for.
	Identity *jwt.IDClaims
}

UserinfoResponse contains information to response to the userinfo response.

Directories

Path Synopsis
oauth2
Package oauth2 implements base primitives for parsing a subset of oauth2 messages and errors
Package oauth2 implements base primitives for parsing a subset of oauth2 messages and errors

Jump to

Keyboard shortcuts

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