Documentation
¶
Overview ¶
Package refresh is an RFC 6749 §6 OAuth 2.0 refresh_token grant client.
Construct a Client with the issuer's BaseURL and the token endpoint path, then call Refresh with a populated Request to re-mint an access token (in auth-go's three-tier model, the login JWT) from a stored refresh token. The package is provider-agnostic: endpoint path and client_id are supplied at call time. There is no provider detection.
Index ¶
Constants ¶
const DefaultRequestTimeout = 30 * time.Second
DefaultRequestTimeout caps a single refresh round-trip. Set conservatively; a healthy refresh completes in sub-seconds. See Client.RequestTimeout for the per-Client override.
Variables ¶
var ( ErrInsecureBaseURL = oauthhttp.ErrInsecureBaseURL ErrAbsolutePath = oauthhttp.ErrAbsolutePath )
ErrInsecureBaseURL / ErrAbsolutePath are re-exported from oauthhttp so callers can errors.Is uniformly across deviceflow / sts / refresh.
var ErrInvalidGrant = errors.New("invalid_grant")
ErrInvalidGrant is returned when the server rejects the refresh token with the RFC 6749 §5.2 invalid_grant code — the token is expired, revoked, or (under rotating-refresh reuse detection) already consumed. Callers branch on this to distinguish a recoverable rotation race from a transport failure.
Functions ¶
func SetNowForTest ¶
SetNowForTest replaces the client's clock with now for the lifetime of the test, restoring the previous override on t.Cleanup. Stored via atomic.Pointer so it doesn't race the hot-path read in Refresh.
Production code should never construct a Client via this path; it is exported for use in test files only.
Types ¶
type Client ¶
type Client struct {
// Transport supplies the http.RoundTripper used for all calls. nil →
// http.DefaultTransport. The library builds its own *http.Client so
// callers can't trivially pass one with TLS verification disabled —
// see sts.Client.Transport for the rationale.
Transport http.RoundTripper
BaseURL string
Path string
UserAgent string
// RequestTimeout is the per-Refresh deadline applied via
// context.WithTimeout on top of the caller's context. Zero → default;
// negative disables the cap.
RequestTimeout time.Duration
// AllowInsecureHTTP permits http:// BaseURLs. Default (false) rejects:
// the refresh request ships the refresh token (a bearer) in the body
// and must be TLS-protected. Only flip for loopback dev/tests.
AllowInsecureHTTP bool
// contains filtered or unexported fields
}
Client runs the refresh_token grant against an RFC 6749 token endpoint.
All configuration is explicit; the package has no global state and no implicit URLs. Mirrors sts.Client's construction and security posture.
func New ¶
New validates a Client's required fields at construction time rather than at the first Refresh call. Returns an error if BaseURL or Path is empty — these would otherwise surface as a confusing URL error from the caller at the worst moment.
Takes a *Client (rather than a Client value) because the struct embeds an atomic.Pointer for the test-clock seam, which can't be copied per the noCopy convention. Returns the same pointer on success.
Field-bag construction (`&refresh.Client{...}`) is still supported for callers who want to set optional fields piecemeal, but New is the recommended path — it makes misconfiguration a startup error rather than a runtime one.
func (*Client) Refresh ¶
Refresh performs one refresh_token grant. Returns a TokenSet whose AccessToken is the freshly minted token and RefreshToken is the rotated successor (empty if the server doesn't rotate). ExpiresAt is derived from expires_in when positive, else left zero — unlike sts.Exchange we tolerate a missing expires_in because the minted login JWT carries its own exp claim.
type Request ¶
Request is the input to a refresh. RefreshToken is required. ClientID, when non-empty, is sent as the Basic-auth username (RFC 6749 §2.3.1) — entire-core/zitadel reads client credentials from the Basic header on the token grants. Callers also typically mirror it into Extra["client_id"] for servers that read the form body. Scope is optional (RFC 6749 §6 allows narrowing; omitted when empty). Extra carries additional form fields; standard fields win over Extra.
Extra values are NOT redacted by String()/GoString() — only RefreshToken is. Do not place bearer-equivalent credentials (client secrets, assertion JWTs) in Extra; this package targets public-client flows where no such field is expected.