Documentation
¶
Overview ¶
Package token manages the on-disk cache of Chainguard OIDC access and refresh tokens, organized by audience and optional alias. Refresh tokens read and written WithIssuer are kept in refresh-token families, one per login, and are exchanged through Refresh, which serializes every process sharing the cache.
Index ¶
- Variables
- func Delete(kind Kind, audience string, opts ...Option) error
- func DeleteAll() error
- func DeleteFamilies() error
- func ListAudiences() ([]string, error)
- func Load(kind Kind, audience string, opts ...Option) ([]byte, error)
- func Path(kind Kind, audience string, opts ...Option) (string, error)
- func Refresh(ctx context.Context, audience string, exchange ExchangeFunc, opts ...Option) error
- func RemainingLife(kind Kind, audience string, less time.Duration, opts ...Option) time.Duration
- func Save(token []byte, kind Kind, audience string, opts ...Option) error
- func SaveFamily(tok []byte, audiences []string, opts ...Option) error
- type ExchangeFunc
- type Kind
- type Option
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( // another process held it past the timeout, the context ended, or the // filesystem does not support locking. Nothing was exchanged. A caller // should fail with a retryable error rather than serve a cached access // token, which may be for another scope, issuer or principal, and must // not exchange the refresh token without the lock. ErrLockUnavailable = errors.New("token: the refresh-token store lock is unavailable") // ErrSuccessorNotStored is returned by Refresh when the exchange succeeded // but the successor it returned could not be written. The family has been // discarded, so the superseded token is never presented again, and the // access token the exchange minted is still valid; the next refresh needs // a new login. ErrSuccessorNotStored = errors.New("token: the rotated refresh token could not be stored") )
var (
AllKinds = []Kind{KindAccess, KindRefresh}
)
Functions ¶
func Delete ¶
Delete removes the token for the given audience, if it exists. No error is returned if the token doesn't exist.
For KindRefresh it also removes audience from the coverage of every family (of the given issuer only, when WithIssuer is passed), deleting a family left covering nothing.
func DeleteAll ¶
func DeleteAll() error
DeleteAll removes all Chainguard tokens and empty audience directories, including every refresh-token family. The store's lock file holds no token and is left in place.
func DeleteFamilies ¶ added in v0.1.424
func DeleteFamilies() error
DeleteFamilies removes every refresh-token family and the per-audience copies of each family's token, leaving other per-audience token files and the store's lock file in place. Every family holds a Chainguard platform refresh token, so a caller clearing platform credentials by walking audience directories needs this as well: a family can cover audiences that have no directory.
func ListAudiences ¶ added in v0.1.164
ListAudiences returns the set of audiences for which an access token (KindAccess) currently exists in the local token cache.
Audiences are recovered from each token's "aud" claim rather than from the on-disk directory name, since the directory name is a lossy encoding of the audience (e.g. "/" is replaced with "-"). The returned slice is sorted and de-duplicated. Files that cannot be read or parsed as tokens are skipped.
func Refresh ¶ added in v0.1.424
Refresh loads the refresh token from the issuer named by WithIssuer that covers audience, passes it to exchange, and stores the successor exchange returns, all while holding a lock shared with every other process using the cache. The token is loaded after the lock is taken, so a process that waited on another's rotation presents the successor, never the parent it would have read before waiting.
It returns exchange's error unchanged, ErrLockUnavailable without calling exchange, an error wrapping fs.ErrNotExist when no token covers audience, or ErrSuccessorNotStored after a successful exchange whose result could not be written.
func RemainingLife ¶
RemainingLife returns the amount of time remaining before the token for the given audience expires. Returns 0 for expired and non-existent tokens.
func Save ¶
Save saves the given token to cache/audience. A KindRefresh token saved WithIssuer is stored as a family covering audience alone, the same as SaveFamily with that one audience.
func SaveFamily ¶ added in v0.1.424
SaveFamily stores tok, a refresh token obtained from the issuer named by WithIssuer, as that issuer's family serving audiences. Those audiences are removed from every other family of that issuer, so each audience resolves to exactly one token, and tok is written to each one's per-audience file unless that file holds a live token from another issuer and the audience is not the one named by WithPrimaryAudience.
The family is recorded under the issuer the caller names, which is where the token is presented, not under the token's iss claim: an issuer reached through another name, such as a cluster-internal issuer behind a mapped domain, mints tokens whose iss is a URL the client never dials.
Types ¶
type ExchangeFunc ¶ added in v0.1.424
ExchangeFunc presents refreshToken to the issuer and returns the refresh token the issuer answered with. Returning "" or refreshToken itself stores nothing, which is how a caller that found it no longer needs an exchange declines one. It runs with the store lock held, so it must not call back into Refresh, SaveFamily or a KindRefresh Save or Delete.
type Option ¶ added in v0.1.44
type Option func(*token)
func WithAlias ¶ added in v0.1.44
WithAlias allows callers to organize tokens into subdirectories under an audience to manage multiple tokens for the same audience without overwriting.
Example ¶
ExampleWithAlias demonstrates creating an Option that sets a token alias.
package main
import (
"fmt"
"chainguard.dev/sdk/auth/token"
)
func main() {
opt := token.WithAlias("my-alias")
fmt.Println(opt != nil)
}
Output: true
func WithIssuer ¶ added in v0.1.424
WithIssuer scopes a refresh token to the issuer that minted it. For KindRefresh, Load and RemainingLife then return only a token from that issuer, resolved through the family store (see SaveFamily), and Save and Delete act on that issuer's families. A caller that passes no issuer sees only the per-audience file, exactly as it would without the family store, and never a family. Other kinds ignore the option, and so do aliased tokens, which never belong to a family.
func WithPrimaryAudience ¶ added in v0.1.424
WithPrimaryAudience names the audience a login was requested for. SaveFamily always writes that audience's per-audience copy, even over a live token from another issuer, which it keeps in every other audience it covers.