Documentation
¶
Overview ¶
Package credentials stores the Credentials of each OAuth Upstream in a file of its own, written only under a lock on a sibling file (ADR 0003).
Index ¶
- Constants
- Variables
- type Binding
- type Credentials
- type LoginNeededError
- type Refresh
- type Source
- type Store
- func (s *Store) Delete(ctx context.Context, upstream string) (bool, error)
- func (s *Store) Load(u config.Upstream) (*Credentials, error)
- func (s *Store) Save(ctx context.Context, upstream string, c *Credentials) error
- func (s *Store) Source(u config.Upstream, refresh Refresh, log *slog.Logger) *Source
- func (s *Store) Wait()
Constants ¶
const ReasonExpired = "the credentials expired and cannot be renewed"
ReasonExpired is why an Upstream whose Credentials are dead (see Credentials.Dead) needs a Login.
Variables ¶
var ErrNoHome = errors.New("cannot locate the credentials: HOME is not set")
ErrNoHome is why NewStore can't return a Store.
var ErrRefreshRejected = errors.New("the authorization server rejected the refresh token")
ErrRefreshRejected is what a Refresh returns when the Authorization Server rejects the refresh token (invalid_grant).
Functions ¶
This section is empty.
Types ¶
type Binding ¶
type Binding struct {
URL string `json:"url"`
ClientID string `json:"client_id,omitempty"` // oauth.clientId
Scopes []string `json:"scopes"` // oauth.scopes; null when the Config has none
}
Binding is what an Upstream's Config said when its Credentials were issued, and must still say for them to be used. oauth.clientSecret is left out, so that rotating it keeps them.
type Credentials ¶
type Credentials struct {
oauth2.Token
Scopes []string `json:"scopes,omitempty"` // granted
TokenURL string `json:"token_url"`
AuthStyle oauth2.AuthStyle `json:"auth_style"`
// The client that Dynamic Client Registration issued, if any.
ClientID string `json:"client_id,omitempty"`
ClientSecret string `json:"client_secret,omitempty"`
// Identity: the canonical URI of the Upstream and the issuer of the
// Authorization Server, and the Config they were issued for.
Resource string `json:"resource"`
Issuer string `json:"issuer"`
Config Binding `json:"config"`
}
Credentials are what a Login leaves behind for one Upstream: its tokens, what is needed to renew them, and the identity they were issued for.
func (*Credentials) Dead ¶
func (c *Credentials) Dead() bool
Dead reports whether c can't be used any more without a new Login: the access token has expired, and there is no refresh token to renew it with.
func (*Credentials) Expired ¶ added in v0.3.0
func (c *Credentials) Expired() bool
Expired reports whether the access token of c has expired.
type LoginNeededError ¶
type LoginNeededError struct {
// Reason is why the Credentials it had can't be used, "" if it had none.
Reason string
}
LoginNeededError is the error of an Upstream that has no Credentials it can use.
func (*LoginNeededError) Error ¶
func (e *LoginNeededError) Error() string
type Refresh ¶
type Refresh func(ctx context.Context, c *Credentials, metadata string) (*Credentials, error)
Refresh gets a new access token for c from their Authorization Server and returns the Credentials it makes. metadata is the URL of the Protected Resource Metadata that the Upstream named when it rejected c, if it did. It returns ErrRefreshRejected when the server rejects the refresh token, and a *LoginNeededError when c can't be used any more; any other error leaves them as they are.
type Source ¶
type Source struct {
// contains filtered or unexported fields
}
Source is the Credentials of one Upstream as one process uses them. It reads them again whenever their file changes, so that a Login, a logout or another process's renewal shows, and renews them with its Refresh only once at a time, both in this process and, through the Store's lock, across processes (ADR 0003).
Token on the nil Source returns no access token.
func (*Source) Rejected ¶
Rejected renews the Credentials whose access token the Upstream answered 401 to, at most once for each token, and returns the new access token. metadata is the URL of the Protected Resource Metadata that the 401 named, if any. A *LoginNeededError means that the Credentials can't be used.
func (*Source) Token ¶
Token returns the access token to send, renewed first if it expires within renewBefore, or "" without Credentials. A *LoginNeededError means that they can't be used.
func (*Source) Unauthorized ¶
Unauthorized returns why the Upstream needs a Login when it answers 401 past Token and Rejected: it has no Credentials, as last read, or rejects them.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store is the directory holding the Credentials of every Upstream.
func NewStore ¶
NewStore returns the Store under $XDG_STATE_HOME/sprut/credentials, or ~/.local/state/sprut/credentials.
func (*Store) Delete ¶
Delete deletes the Credentials of upstream under its lock, and reports whether there were any. The lock file stays. When there are none, it takes no lock, so that it creates no lock file: a Save that is writing them meanwhile would have outlived a locked Delete just as well, had it taken the lock a moment later.
func (*Store) Load ¶
func (s *Store) Load(u config.Upstream) (*Credentials, error)
Load returns the Credentials of u, or nil if it has none, or none issued for u as its Config is now.