Documentation
¶
Overview ¶
Package memory keeps an authorization server's state in maps.
store := memory.NewStore(memory.WithSweeper(ctx, oauth2server.DefaultSweepInterval)) srv, _ := oauth2server.NewServer(cfg, store, authenticator)
It exists for tests, for a single-process development server, and for nothing else — and saying so is the point of the package rather than a caveat on it, because a map-backed authorization server is exactly what a consumer assembling this from the reference examples ends up with, and it looks like it works.
What it cannot do ¶
An authorization code is issued by the replica that served /authorize and redeemed by whichever replica serves /token. With this store those are the same process or the redemption fails, so a fleet behind a load balancer fails logins in proportion to how well the balancer spreads them — which reads as a flaky login rather than as a missing dependency.
A restart drops every registered client. Under RFC 7591 dynamic registration that is every client there is, so a deploy invalidates the entire client population and each one has to discover and re-register before its next login works.
oauth2server/database is the answer to both, and it is the same interface.
What it does do ¶
Everything the interface promises, atomically, under one mutex. It passes the same oauth2servertest suite the database store does, including the case where two goroutines redeem one authorization code and exactly one of them wins. That is why it is a usable test double rather than a shape that compiles: a suite that schedules against this store inherits whatever it gets wrong, so it is held to the same contract as the real thing.
Index ¶
- type Option
- type Store
- func (s *Store) Close() error
- func (s *Store) ConsumeAuthorizationCode(ctx context.Context, hash string) (*oauth2server.AuthorizationCode, error)
- func (s *Store) ConsumeRefreshToken(ctx context.Context, hash string) (*oauth2server.RefreshToken, error)
- func (s *Store) CreateAccessToken(ctx context.Context, token *oauth2server.AccessToken) error
- func (s *Store) CreateAuthorizationCode(ctx context.Context, code *oauth2server.AuthorizationCode) error
- func (s *Store) CreateClient(ctx context.Context, client *oauth2server.Client) error
- func (s *Store) CreateRefreshToken(ctx context.Context, token *oauth2server.RefreshToken) error
- func (s *Store) DeleteClient(ctx context.Context, clientID string) error
- func (s *Store) GetAccessToken(ctx context.Context, hash string) (*oauth2server.AccessToken, error)
- func (s *Store) GetClient(ctx context.Context, clientID string) (*oauth2server.Client, error)
- func (s *Store) GetRefreshToken(ctx context.Context, hash string) (*oauth2server.RefreshToken, error)
- func (s *Store) RevokeAccessToken(ctx context.Context, hash string) error
- func (s *Store) RevokeFamily(ctx context.Context, familyID string) (int64, error)
- func (s *Store) RevokeRefreshToken(ctx context.Context, hash string) error
- func (s *Store) Sweep(ctx context.Context, now time.Time) (int64, error)
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Option ¶
type Option func(*options)
Option configures a Store at construction.
func WithClock ¶
WithClock swaps the clock this store stamps and expires against, so a test can move expiry without waiting for it.
func WithLogger ¶
WithLogger attaches a logger. An absent logger logs nowhere.
func WithSweeper ¶
WithSweeper starts a background sweep that removes dead records every interval, until ctx is done.
It matters less here than it does for the database store — this store's maps die with the process — but a long-lived single-process deployment still accumulates one authorization code per login attempt forever without it.
A nil context or a non-positive interval starts nothing.
func WithTracerProvider ¶
WithTracerProvider attaches a tracer provider. An absent one traces nowhere.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store keeps every authorization server record in maps behind one mutex.
One mutex rather than one per map, because the operations that matter span maps: revoking a family touches both token maps, and consuming a code has to be atomic against everything else. Four locks would make that a lock-ordering problem in a type whose entire job is to be the simple one.
func NewStore ¶
NewStore builds an in-memory Store.
It is for tests, for single-process development, and for nothing else. Two replicas do not share it, which under this package's flow means the authorization code issued by one replica cannot be redeemed at the other — so a login fails whenever the load balancer does its job. A restart loses every registered client, which under dynamic registration is every client there is. Deployments want oauth2server/database.
func (*Store) ConsumeAuthorizationCode ¶
func (s *Store) ConsumeAuthorizationCode(ctx context.Context, hash string) (*oauth2server.AuthorizationCode, error)
ConsumeAuthorizationCode marks a code redeemed and returns it.
The whole method runs under the mutex, which is what makes two concurrent redemptions of one code resolve to exactly one success — the case the conformance suite exists to hold every implementation to.
func (*Store) ConsumeRefreshToken ¶
func (s *Store) ConsumeRefreshToken(ctx context.Context, hash string) (*oauth2server.RefreshToken, error)
ConsumeRefreshToken marks a refresh token redeemed and returns it.
func (*Store) CreateAccessToken ¶
func (s *Store) CreateAccessToken(ctx context.Context, token *oauth2server.AccessToken) error
CreateAccessToken records an issued access token.
func (*Store) CreateAuthorizationCode ¶
func (s *Store) CreateAuthorizationCode(ctx context.Context, code *oauth2server.AuthorizationCode) error
CreateAuthorizationCode records an issued code.
func (*Store) CreateClient ¶
CreateClient records a registration.
func (*Store) CreateRefreshToken ¶
func (s *Store) CreateRefreshToken(ctx context.Context, token *oauth2server.RefreshToken) error
CreateRefreshToken records an issued refresh token.
func (*Store) DeleteClient ¶
DeleteClient removes a registration. Absent is not an error.
func (*Store) GetAccessToken ¶
func (s *Store) GetAccessToken(ctx context.Context, hash string) (*oauth2server.AccessToken, error)
GetAccessToken reads an access token.
func (*Store) GetRefreshToken ¶
func (s *Store) GetRefreshToken(ctx context.Context, hash string) (*oauth2server.RefreshToken, error)
GetRefreshToken reads a refresh token without consuming it.
func (*Store) RevokeAccessToken ¶
RevokeAccessToken marks one access token revoked. Absent is not an error.
func (*Store) RevokeFamily ¶
RevokeFamily revokes every access and refresh token in a family.
func (*Store) RevokeRefreshToken ¶
RevokeRefreshToken marks one refresh token revoked. Absent is not an error.
func (*Store) Sweep ¶
Sweep removes records whose deadlines have passed.
Revoked-but-unexpired tokens are deliberately kept: a resource server holding one is entitled to be told "no" rather than to have its request treated as carrying a token nobody ever issued, and the difference shows up in whichever log line an operator reads when a user complains that signing out did not work.