oauth

package
v1.23.1 Latest Latest
Warning

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

Go to latest
Published: Nov 4, 2026 License: MIT Imports: 8 Imported by: 0

Documentation

Overview

Package oauth is an OAuth 2.1 authorization server for the resources of the apps a sign-in service fronts -- an app's MCP server, say -- beside the service's own sessions rather than in place of them.

Its tokens are for those resources alone. An access token names one resource as its audience and is signed with a key of its own, not the session key, so no service that accepts the sign-in service's sessions accepts one; and the flow that issues one never issues a session. The user is identified by the session they already have, through the sign-in the service already offers.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrNotFound is a request, code, refresh token or grant that does not exist, has expired or
	// has been revoked: to the client, all the same.
	ErrNotFound = errors.New("not found")

	// ErrRefreshTokenReused is a refresh token presented after it was spent. Its grant is revoked:
	// only one of the two presenting it can be the client.
	ErrRefreshTokenReused = errors.New("refresh token reused")
)

Functions

func AuthorizationResponseUrl

func AuthorizationResponseUrl(redirectUri string, issuer string, parameters map[string]string) (string, error)

AuthorizationResponseUrl is the redirect URI with the authorization response's parameters added to what query it has, and the issuer among them (RFC 9207), which tells a client talking to several servers which one answered.

func HashSecret

func HashSecret(secret string) []byte

HashSecret is what a secret is kept as: its SHA-256. A store's copy is then nothing anyone could present.

func NewSecret

func NewSecret() (string, error)

NewSecret is a value the server hands out to be presented back -- a code or a refresh token: 32 random bytes, base64url.

Types

type AuthorizationCode

type AuthorizationCode struct {
	AccountId     string
	ClientId      string
	RedirectUri   string
	CodeChallenge string
	Resource      string
	Scope         string
	ExpiresAt     time.Time
}

AuthorizationCode is what an authorization code stands for, held under the code's hash until it is redeemed.

type AuthorizationRequest

type AuthorizationRequest struct {
	Id            string
	AccountId     string
	ClientId      string
	ClientName    string
	RedirectUri   string
	State         string
	CodeChallenge string
	Resource      string
	Scope         string
	ExpiresAt     time.Time
}

AuthorizationRequest is an authorization request held between the consent page and the user's answer to it.

type Grant

type Grant struct {
	Id        string
	AccountId string
	ClientId  string
	Resource  string
	Scope     string
	// KeyThumbprint binds the grant's tokens to a key (RFC 9449), for a client that has one.
	KeyThumbprint string
	CreatedAt     time.Time
}

Grant is a client's standing access to one resource on an account's behalf, which its refresh tokens renew and revoking ends.

type GrantCheck

type GrantCheck func(grant *Grant) error

GrantCheck is what a grant must pass to be renewed. It is asked while the refresh token is held, and may ask the store about the account, so a store asks it without holding a lock of its own.

type Resource

type Resource struct {
	Url string `json:"url"`
	// Name is what the consent page calls it.
	Name string `json:"name"`
	// Scopes are the scopes a token for it may carry; a request naming none is given all of them.
	Scopes []string `json:"scopes"`
}

Resource is what an access token may be issued for: an app's protected resource, named by its URL (RFC 8707), which is the token's audience.

func FindResource

func FindResource(resources []*Resource, url string) *Resource

FindResource is the resource of the URL among resources. A request naming no resource is given the only one there is, and refused where there are several: guessing which would be guessing what the user is asked to consent to.

func (*Resource) AllowsScopes

func (r *Resource) AllowsScopes(scopes []string) bool

AllowsScopes says whether every scope asked for is one the resource has.

type Store

type Store interface {
	InsertAuthorizationRequest(ctx context.Context, request *AuthorizationRequest) (string, error)
	// PopAuthorizationRequest returns the request and removes it, or ErrNotFound.
	PopAuthorizationRequest(ctx context.Context, id string) (*AuthorizationRequest, error)

	InsertAuthorizationCode(ctx context.Context, codeHash []byte, code *AuthorizationCode) error
	// PopAuthorizationCode returns what the code stands for and removes it, or ErrNotFound: a code
	// is redeemed once.
	PopAuthorizationCode(ctx context.Context, codeHash []byte) (*AuthorizationCode, error)

	// InsertGrant records a grant and its first refresh token, returning the grant's id.
	InsertGrant(ctx context.Context, grant *Grant, refreshTokenHash []byte, refreshTokenExpiresAt time.Time) (string, error)
	// RotateRefreshToken spends a refresh token and records its successor in one step, returning
	// the grant it renews. A token spent before revokes the grant and is ErrRefreshTokenReused; one
	// unknown, expired, or of a revoked grant is ErrNotFound. check is asked of the grant before the
	// token is spent, and an error from it is returned with the token left as it was: a refusal must
	// not cost the client the only token it has.
	RotateRefreshToken(
		ctx context.Context,
		refreshTokenHash []byte,
		newRefreshTokenHash []byte,
		newExpiresAt time.Time,
		now time.Time,
		check GrantCheck,
	) (*Grant, error)
	// RevokeRefreshToken revokes the grant the refresh token renews, spent or not. A token not
	// known is no error: there is nothing left to revoke.
	RevokeRefreshToken(ctx context.Context, refreshTokenHash []byte) error

	// AccountActive says whether the account exists and is not locked.
	AccountActive(ctx context.Context, accountId string) (bool, error)
}

Store keeps what the authorization server hands out. Codes and refresh tokens are kept by their hashes, never as themselves.

Directories

Path Synopsis
Package testing holds what tests of the OAuth authorization server share: the behaviour every store must have, as a test any of them can be run through.
Package testing holds what tests of the OAuth authorization server share: the behaviour every store must have, as a test any of them can be run through.
types
access_token
Package access_token is an OAuth access token as the authorization server issues it: a JWT (RFC 9068) for one resource, signed with a key of its own.
Package access_token is an OAuth access token as the authorization server issues it: a JWT (RFC 9068) for one resource, signed with a key of its own.
access_token_parser
Package access_token_parser is how a resource accepts the authorization server's access tokens: a request parser that takes a bearer token only of the server's type, signed with its key, for this resource and with the scope the resource requires.
Package access_token_parser is how a resource accepts the authorization server's access tokens: a request parser that takes a bearer token only of the server's type, signed with its key, for this resource and with the scope the resource requires.
cimd_fetcher
Package cimd_fetcher reads a client's metadata document (Client ID Metadata Documents, as the MCP authorization specification has clients register): a client's id is the HTTPS URL of a JSON document saying what the client is called and where it may be sent back to, which the authorization server fetches when the client first asks for authorization.
Package cimd_fetcher reads a client's metadata document (Client ID Metadata Documents, as the MCP authorization specification has clients register): a client's id is the HTTPS URL of a JSON document saying what the client is called and where it may be sent back to, which the authorization server fetches when the client first asks for authorization.
client
Package client is an OAuth client as the authorization server knows it: what it is called and where it may be sent back to.
Package client is an OAuth client as the authorization server knows it: what it is called and where it may be sent back to.
client_registrar
Package client_registrar is dynamic client registration (RFC 7591) without a store: a client's id is what it registered, signed, and resolving it is checking the signature and reading it back.
Package client_registrar is dynamic client registration (RFC 7591) without a store: a client's id is what it registered, signed, and resolving it is checking the signature and reading it back.
client_resolver
Package client_resolver is how the authorization server knows a client: one registered with it beforehand, one that registered itself and holds the id it was given, or one whose id is the URL of a metadata document on a host it allows.
Package client_resolver is how the authorization server knows a client: one registered with it beforehand, one that registered itself and holds the id it was given, or one whose id is the URL of a metadata document on a host it allows.
endpoint/authorization_server_metadata_endpoint
Package authorization_server_metadata_endpoint serves the authorization server's metadata (RFC 8414), which is how a client learns where to send the user and where to redeem a code, and what the server supports -- among it that a client may register by its metadata document, which is what has Claude use one rather than register dynamically.
Package authorization_server_metadata_endpoint serves the authorization server's metadata (RFC 8414), which is how a client learns where to send the user and where to redeem a code, and what the server supports -- among it that a client may register by its metadata document, which is what has Claude use one rather than register dynamically.
endpoint/authorize_endpoint
Package authorize_endpoint is the authorization endpoint (RFC 6749 section 3.1, OAuth 2.1): where a client sends the user to be asked whether it may act for them on a resource.
Package authorize_endpoint is the authorization endpoint (RFC 6749 section 3.1, OAuth 2.1): where a client sends the user to be asked whether it may act for them on a resource.
endpoint/decision_endpoint
Package decision_endpoint takes the user's answer to the consent page: on allowing, an authorization code for the client; on denying, the refusal.
Package decision_endpoint takes the user's answer to the consent page: on allowing, an authorization code for the client; on denying, the refusal.
endpoint/protected_resource_metadata_endpoint
Package protected_resource_metadata_endpoint serves a resource's metadata (RFC 9728), which is how a client that was refused by the resource learns which authorization server to ask, and for what scope.
Package protected_resource_metadata_endpoint serves a resource's metadata (RFC 9728), which is how a client that was refused by the resource learns which authorization server to ask, and for what scope.
endpoint/registration_endpoint
Package registration_endpoint is the client registration endpoint (RFC 7591): where a client with no metadata document of its own -- Gemini's -- registers, and is given an id.
Package registration_endpoint is the client registration endpoint (RFC 7591): where a client with no metadata document of its own -- Gemini's -- registers, and is given an id.
endpoint/revocation_endpoint
Package revocation_endpoint is the revocation endpoint (RFC 7009): where a client gives up what it was granted, as Claude does when the user removes a connector.
Package revocation_endpoint is the revocation endpoint (RFC 7009): where a client gives up what it was granted, as Claude does when the user removes a connector.
endpoint/token_endpoint
Package token_endpoint is the token endpoint (RFC 6749 section 3.2, OAuth 2.1): where a client redeems an authorization code, or a refresh token, for an access token to a resource.
Package token_endpoint is the token endpoint (RFC 6749 section 3.2, OAuth 2.1): where a client redeems an authorization code, or a refresh token, for an access token to a resource.
memory_store
Package memory_store keeps what the OAuth authorization server hands out in memory, for tests: nothing expired is ever swept, so a server kept running on it would grow without end.
Package memory_store keeps what the OAuth authorization server hands out in memory, for tests: nothing expired is ever swept, so a server kept running on it would grow without end.
page
Package page is the authorization server's pages: the consent page, and the message a request is refused with where it cannot be sent back to its client.
Package page is the authorization server's pages: the consent page, and the message a request is refused with where it cannot be sent back to its client.
postgres_store
Package postgres_store keeps what the OAuth authorization server hands out in the tables of database/types/oauth_authorization, alongside the service's accounts.
Package postgres_store keeps what the OAuth authorization server hands out in the tables of database/types/oauth_authorization, alongside the service's accounts.

Jump to

Keyboard shortcuts

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