refresh

package
v0.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 28, 2026 License: MIT Imports: 10 Imported by: 0

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

View Source
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

View Source
var (
	ErrInsecureBaseURL = oauthhttp.ErrInsecureBaseURL
	ErrAbsolutePath    = oauthhttp.ErrAbsolutePath
)

ErrInsecureBaseURL / ErrAbsolutePath are re-exported from oauthhttp so callers can errors.Is uniformly across deviceflow / sts / refresh.

View Source
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

func SetNowForTest(t TestingTB, c *Client, now func() time.Time)

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

func New(c *Client) (*Client, error)

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

func (c *Client) Refresh(ctx context.Context, req Request) (*tokens.TokenSet, error)

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

type Request struct {
	RefreshToken string
	ClientID     string
	Scope        string
	Extra        url.Values
}

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.

func (Request) GoString

func (r Request) GoString() string

GoString delegates to String so %#v also redacts.

func (Request) String

func (r Request) String() string

String redacts RefreshToken so an accidental log/print doesn't leak the bearer. ClientID is an identifier, shown verbatim.

type TestingTB

type TestingTB interface {
	Helper()
	Cleanup(func())
}

TestingTB is the subset of testing.TB used by SetNowForTest.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL