oauth

package
v1.0.48365 Latest Latest
Warning

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

Go to latest
Published: Aug 18, 2026 License: MIT Imports: 15 Imported by: 0

Documentation

Overview

Package oauth implements the client side of the CircleCI OAuth 2.0 Authorization Code + PKCE flow (RFC 6749 + RFC 7636 + RFC 8252) with Pushed Authorization Requests (RFC 9126).

The flow:

  1. Start a localhost listener on 127.0.0.1:0.
  2. Assemble the authorization request — PKCE code challenge, state, and the loopback redirect_uri — and POST it to the server's PAR endpoint (/oauth/par), which returns a request_uri.
  3. Build a short authorize URL carrying only client_id and request_uri.
  4. The caller opens that URL in the user's browser.
  5. Wait for the OAuth provider to redirect to the loopback server with ?code=...&state=... and validate the state.
  6. Exchange the captured code (with the PKCE verifier) for a token via POST /oauth/token.

Pushing the request keeps sensitive parameters off the browser URL and makes the URL short enough to log and click.

Two entry points share the same underlying flow:

  • Start lands the user on the OAuth login page.
  • StartSignup appends signup=true so unauthenticated users land on the signup page instead. Everything past the authorize step is identical.

Index

Constants

View Source
const ClientID = "circleci-cli"

ClientID is the CircleCI-registered OAuth client identifier for the CLI.

Variables

This section is empty.

Functions

This section is empty.

Types

type Flow

type Flow struct {
	// AuthorizeURL is the URL the user's browser must visit to start the flow.
	AuthorizeURL string
	// contains filtered or unexported fields
}

Flow is an in-progress authorization-code+PKCE exchange.

Typical usage:

flow, err := oauth.Start(ctx, host)
if err != nil { ... }
defer flow.Close()
// open flow.AuthorizeURL in the user's browser
res, err := flow.Wait(ctx)

func Start

func Start(ctx context.Context, host, deviceID, osInfo string) (*Flow, error)

Start binds a loopback listener, generates PKCE + state, and returns a Flow whose AuthorizeURL the caller should open in the user's browser. The returned Flow owns the listener and HTTP server until Close is called.

host is the CircleCI base URL (e.g. https://circleci.com). The OAuth endpoints are derived as host + /oauth/authorize and host + /oauth/token. deviceID and osInfo are appended as query parameters on the authorize URL so the server can correlate requests by CLI installation and platform.

func StartSignup

func StartSignup(ctx context.Context, host, deviceID, osInfo string) (*Flow, error)

StartSignup is like Start, but appends signup=true to the authorize URL so the OAuth provider routes unauthenticated users to the signup page rather than the login page. The PKCE handshake, loopback callback, and token exchange are otherwise identical.

func (*Flow) Close

func (f *Flow) Close() error

Close shuts down the loopback server. Safe to call multiple times.

func (*Flow) Exchange

func (f *Flow) Exchange(ctx context.Context, code string) (*TokenResponse, error)

Exchange swaps an authorization code for an access token by POSTing to the configured /oauth/token endpoint with PKCE verifier. The verifier captured during Start is reused.

func (*Flow) Wait

func (f *Flow) Wait(ctx context.Context) (*Result, error)

Wait blocks until the loopback server receives a callback from the OAuth provider, ctx is cancelled, or the result is otherwise resolved.

type Result

type Result struct {
	Code     string
	Verifier string
}

Result is the outcome of a successful authorization. The Verifier must be presented when exchanging Code for an access token.

type TokenResponse

type TokenResponse struct {
	AccessToken  string `json:"access_token"`
	TokenType    string `json:"token_type,omitempty"`
	ExpiresIn    int64  `json:"expires_in,omitempty"`
	RefreshToken string `json:"refresh_token,omitempty"`
}

TokenResponse is the parsed response from POST /oauth/token. It mirrors the OAuth 2.0 wire format; we expose this rather than oauth2.Token directly so the JSON output is deterministic (oauth2.Token.Expiry is computed from time.Now() at parse time, which makes it non-reproducible across runs).

Jump to

Keyboard shortcuts

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