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 ¶
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 ¶
HashSecret is what a secret is kept as: its SHA-256. A store's copy is then nothing anyone could present.
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 ¶
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 ¶
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 ¶
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. |