auth

package
v1.32.0 Latest Latest
Warning

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

Go to latest
Published: Jul 20, 2026 License: Apache-2.0 Imports: 14 Imported by: 0

Documentation

Overview

Package auth implements pvtr's OIDC device-grant login and credential storage for authenticated publishing to grc.store. It mirrors grcli's flow (ADR-0028): a device-authorization grant against the hub-advertised OIDC issuer + client, with tokens cached in a 0600 file under the XDG data dir. The consumer (install) path stays anonymous and does not touch this package.

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrAccessDenied      = errors.New("authorization denied by the user")
	ErrExpiredDeviceCode = errors.New("device code expired before authorization completed; run `pvtr login` again")
)

User-facing sentinel errors from the device flow.

View Source
var ErrNoCredentials = errors.New("no stored credentials for this issuer (run `pvtr login`)")

ErrNoCredentials is returned by Get when no entry exists for the issuer.

Functions

func BearerToken

func BearerToken(ctx context.Context, issuer, clientID string) (string, error)

BearerToken resolves an OIDC bearer to authenticate registry/hub writes. Resolution order (highest first):

  1. PVTR_TOKEN env — an explicit token (CI trusted-publishing's GHA-OIDC token, or a manually minted one). No store interaction.
  2. The device-grant store for the given issuer, refreshing if near expiry.

Returns ErrNoCredentials when neither is available — callers map that to "run `pvtr login` (or set PVTR_TOKEN in CI)".

func Login

func Login(ctx context.Context, issuer, clientID string, promptOut io.Writer) (string, error)

Login runs the device-authorization grant against the issuer and stores the resulting credentials. promptOut receives the user-facing "open this URL, enter this code" message. It returns the canonical issuer it logged into.

func Logout

func Logout(issuer string) error

Logout forgets stored credentials for the issuer.

func SigningIDToken

func SigningIDToken(ctx context.Context, promptOut io.Writer) (string, error)

SigningIDToken returns an OIDC ID token suitable for PUBLIC-GOOD Fulcio — the identity the keyless plugin signature is minted under. This is DISTINCT from BearerToken (the grc.store registry/hub login): Fulcio only trusts public OIDC issuers (GitHub Actions, GitLab, Google, the interactive sigstore Dex), not the grc.store Keycloak.

Resolution order (highest first):

  1. SIGSTORE_ID_TOKEN env — an explicit OIDC token with audience "sigstore". The headless escape hatch for any CI that can mint one (e.g. GitLab CI's `id_tokens`), checked first so an explicit override wins over ambient detection — mirroring how PVTR_TOKEN overrides the bearer.
  2. GitHub Actions ambient OIDC — mints an aud=sigstore token from the runner's token service (a SEPARATE request from the hub bearer).
  3. Interactive sigstore browser sign-in — a SECOND browser auth on top of `pvtr login`, inherent to keyless signing. Skipped with an actionable error when stdin is not a TTY, so CI fails fast instead of hanging on a flow no one can complete.

promptOut receives any interactive instructions.

Types

type Credentials

type Credentials struct {
	Issuer       string    `json:"issuer"`
	AccessToken  string    `json:"access_token"`
	RefreshToken string    `json:"refresh_token,omitempty"`
	TokenType    string    `json:"token_type,omitempty"`
	ExpiresAt    time.Time `json:"expires_at"`
}

Credentials is one issuer's saved tokens. Issuer doubles as the store key.

func PollForToken

func PollForToken(ctx context.Context, meta *OIDCMetadata, clientID string, da *DeviceAuthorization) (*Credentials, error)

PollForToken blocks polling the token endpoint until the device flow completes, returning the issued Credentials.

func (*Credentials) Expired

func (c *Credentials) Expired() bool

Expired reports whether the access token is at/near expiry (within the renewal window), so callers refresh before a push rather than mid-flight.

type DeviceAuthorization

type DeviceAuthorization struct {
	DeviceCode              string `json:"device_code"`
	UserCode                string `json:"user_code"`
	VerificationURI         string `json:"verification_uri"`
	VerificationURIComplete string `json:"verification_uri_complete,omitempty"`
	ExpiresIn               int    `json:"expires_in"`
	Interval                int    `json:"interval"`
}

DeviceAuthorization is RFC 8628 §3.2's device authorization response.

func StartDeviceFlow

func StartDeviceFlow(ctx context.Context, meta *OIDCMetadata, clientID string) (*DeviceAuthorization, error)

StartDeviceFlow calls the device_authorization_endpoint. The caller displays user_code + verification_uri, then hands the result to PollForToken.

type OIDCMetadata

type OIDCMetadata struct {
	Issuer                      string `json:"issuer"`
	DeviceAuthorizationEndpoint string `json:"device_authorization_endpoint"`
	TokenEndpoint               string `json:"token_endpoint"`
}

OIDCMetadata is the subset of the issuer's OpenID Connect discovery document pvtr's device-grant flow needs.

func FetchOIDCMetadata

func FetchOIDCMetadata(ctx context.Context, issuerURL string) (*OIDCMetadata, error)

FetchOIDCMetadata loads <issuer>/.well-known/openid-configuration. issuerURL is the hub-advertised oidc_issuer (NOT the hub URL).

type Store

type Store struct {
	Path string
}

Store is pvtr's on-disk credential cache: a single JSON file at ${XDG_DATA_HOME:-~/.local/share}/pvtr/credentials.json, 0600, one entry per issuer. Same posture as grcli/gh/flyctl. Kept separate from grcli's store so the two tools don't fight over one file.

func NewDefaultStore

func NewDefaultStore() (*Store, error)

NewDefaultStore returns a Store at the standard XDG path.

func (*Store) Delete

func (s *Store) Delete(issuer string) error

Delete removes the entry for issuer; a missing entry is not an error.

func (*Store) Get

func (s *Store) Get(issuer string) (*Credentials, error)

Get returns the credentials saved for issuer, or ErrNoCredentials.

func (*Store) Put

func (s *Store) Put(creds *Credentials) error

Put writes creds.Issuer → creds, replacing any existing entry. The file is rewritten atomically (temp + rename) with 0600 perms. NOTE: intentionally does NOT use utils.WriteFileAtomic — credentials require os.CreateTemp (kernel-assigned unique name) + os.File.Chmod(0600) before any write, so the 0600 mode is set before secret bytes land on disk. The shared helper's WriteFile+rename sequence cannot provide that ordering guarantee.

Jump to

Keyboard shortcuts

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