Documentation
¶
Overview ¶
Package codexauth implements the OAuth2 + PKCE authentication flow for ChatGPT's Codex subscription, token storage and refresh, and the RoundTripper that injects bearer credentials into Responses-API requests.
All constants are verbatim from the registered OpenAI OAuth application. Do not modify them — they are correctness anchors that tie to the live auth.openai.com configuration.
Package codexauth authenticates ChatGPT subscription-backed Codex clients.
The package provides a focused Go library for obtaining an *http.Client that calls the Codex Responses endpoint with a refreshing bearer token and for fetching the authenticated account's picker-visible catalog through Client.ListModels. It is not a CLI, daemon, JSON-RPC server, credential broker, Eino ChatModel wrapper, or provider-classification layer.
JWT handling is intentionally passive. ExtractAccountID decodes claims so the account identifier can be cached with credentials, but it does not verify the JWT signature, issuer, audience, expiry, not-before time, or any other trust boundary. Treat decoded claims as local metadata from an OAuth response that has already been accepted, not as standalone proof of identity.
The credential store writes auth.json with mode 0600 and tightens its parent directory to 0700 on platforms where POSIX modes apply. Logout performs best-effort RFC 7009 refresh-token revocation before deleting local OpenAI credentials, and the revocation HTTP client refuses redirects so a token POST body is not replayed to another target.
The transport refreshes tokens 60 seconds before expiry and coalesces concurrent refresh attempts with singleflight. Client.ListModels additionally serializes its complete operation per Client so separate short-lived transports cannot rotate the same stale refresh token concurrently. It does not retry ordinary 401 responses as a refresh signal; refresh and invalid_grant recovery are handled through the explicit token-refresh path.
See README.md for tutorials and migration examples.
Index ¶
- Constants
- Variables
- func BuildAuthorizeURL(challenge, state string) string
- func ChallengeFromVerifier(v string) string
- func ClassifyCodexError(err error) error
- func Delete(provider string) error
- func ExtractAccountID(idToken string) string
- func GenerateState() (string, error)
- func GenerateVerifier() (string, error)
- func HTTPClient(_ context.Context) (*http.Client, error)deprecated
- func IsCodexAllowed(model string) bool
- func Logout(ctx context.Context) errordeprecated
- func Path() (string, error)
- func Save(af AuthFile) error
- func StartCallbackServer(ctx context.Context, state string) (codeCh <-chan string, errCh <-chan error, shutdown func(), err error)
- type AuthError
- type AuthFile
- type Client
- func (c *Client) HTTPClient(_ context.Context) (*http.Client, error)
- func (c *Client) ListModels(ctx context.Context, clientVersion string) ([]ModelCatalogEntry, error)
- func (c *Client) Login(ctx context.Context, forceDevice bool) (Credentials, error)
- func (c *Client) LoginBrowser(ctx context.Context) (Credentials, error)
- func (c *Client) LoginDevice(ctx context.Context) (Credentials, error)
- func (c *Client) Logout(ctx context.Context) error
- func (c *Client) Path() (string, error)
- func (c *Client) Status(ctx context.Context) (StatusInfo, error)
- type Credentials
- func ExchangeCode(ctx context.Context, code, verifier, redirectURI string) (Credentials, error)
- func Login(ctx context.Context, forceDevice bool) (Credentials, error)deprecated
- func LoginBrowser(ctx context.Context) (Credentials, error)deprecated
- func LoginDevice(ctx context.Context) (Credentials, error)deprecated
- func RefreshToken(ctx context.Context, refreshTok string) (Credentials, error)
- type DeviceError
- type ModelCatalogEntry
- type ModelCatalogHTTPError
- type Options
- type PortInUseError
- type ReasoningEffortOption
- type StatusInfo
Examples ¶
Constants ¶
const ( // ClientID is the OAuth application client identifier registered with // auth.openai.com. Used in every OAuth request. ClientID = "app_EMoamEEZ73f0CkXaXp7hrann" // Issuer is the base URL of the OpenAI authorization server. Issuer = "https://auth.openai.com" // CodexEndpoint is the Responses-API endpoint for Codex inference. CodexEndpoint = "https://chatgpt.com/backend-api/codex/responses" // OAuthPort is the local callback server port used during the browser // OAuth flow. OAuthPort = 1455 // RedirectURI is the registered OAuth redirect URI for the browser flow. RedirectURI = "http://localhost:1455/auth/callback" // Scope is the OAuth scope string requested for Codex access. Scope = "openid profile email offline_access" // PKCEMethod is the PKCE code challenge method. S256 is mandatory per // RFC 7636 §4.2 for public clients. PKCEMethod = "S256" // Originator is the literal value preserved from the source package's wire // behavior. Consumers must not change it without a verified wire trace // proving a different value is accepted; v0.2.0 may move it to Options. Originator = "advisor" // DeviceRedirectURI is the redirect_uri used when exchanging an authorization // code obtained from the device poll endpoint. The server expects this exact // value for codes issued via /api/accounts/deviceauth/token. DeviceRedirectURI = "https://auth.openai.com/deviceauth/callback" )
Variables ¶
var ErrAuthorizationDenied = errors.New("codexauth: authorization denied")
ErrAuthorizationDenied is sent on errCh when the authorization server redirects back with an ?error= parameter (e.g. "access_denied"). It wraps the raw OAuth error string so callers can errors.Is on the sentinel while still surfacing the details in log output.
var ErrInsecureEndpoint = errors.New("codexauth: refusing cleartext http endpoint to non-loopback host")
ErrInsecureEndpoint is returned by HTTPClient or ListModels when Options.Endpoint uses cleartext http:// to a non-loopback host (which would leak the bearer token).
var ErrNoBrowser = errors.New("codexauth: no browser launcher found")
ErrNoBrowser is returned by openBrowser when no suitable browser-launcher binary can be found on the current platform. Callers should treat any non-nil error from openBrowser as a signal to print the URL for the user to copy — ErrNoBrowser specifically indicates the launcher binary was absent, but darwin and windows implementations may return other exec errors on failure.
var ErrNotLoggedIn = errors.New("codexauth: not logged in")
ErrNotLoggedIn is returned by HTTPClient or ListModels when no OpenAI credentials are stored. Callers should check with errors.Is and prompt the user to run Login.
var ErrPlanNotIncluded = errors.New("codexauth: plan not included")
ErrPlanNotIncluded marks Codex API responses where the authenticated account does not have Codex subscription access.
var ErrQuotaExceeded = errors.New("codexauth: quota exceeded")
ErrQuotaExceeded marks Codex API responses where the authenticated account has exhausted its Codex quota.
var ErrRefreshFailed = errors.New("codexauth: refresh failed")
ErrRefreshFailed marks failures while refreshing stored Codex credentials. ListModels uses it for remote refresh failures whose details are not safe to expose; recognized OAuth errors remain inspectable as a sanitized AuthError.
var ErrStateMismatch = errors.New("codexauth: OAuth callback state mismatch")
ErrStateMismatch is sent on errCh when the OAuth callback arrives with a state parameter that does not match the value passed to StartCallbackServer. The caller should treat this as a potential CSRF attempt and abort the flow.
var Version = "0.0.0-dev"
Version is the User-Agent version string. Declared as a var so it can be overridden via -ldflags -X. TODO: replace with internal/version.Version() once that package exists.
Functions ¶
func BuildAuthorizeURL ¶
BuildAuthorizeURL constructs the OAuth2 authorization URL for the Codex subscription browser flow. All fixed parameters (client_id, redirect_uri, scope, originator, etc.) are sourced from the package constants so that the call site only supplies the per-flow values: the PKCE code challenge and the CSRF state token.
The returned URL is ready to open in a browser; the user will be directed to auth.openai.com to approve the Codex subscription scope.
Required params and their sources:
- client_id, redirect_uri, scope, code_challenge_method → package constants
- id_token_add_organizations, codex_cli_simplified_flow → hardcoded "true"
- originator → hardcoded "advisor"
- code_challenge, state → caller-supplied
func ChallengeFromVerifier ¶
ChallengeFromVerifier computes the PKCE S256 code challenge from a verifier string. Returns base64url(sha256(verifier)) with no padding, as required by RFC 7636 §4.2.
func ClassifyCodexError ¶ added in v0.2.0
ClassifyCodexError maps Codex API error codes to exported auth sentinels.
Errors with a Code field matching "usage_not_included" wrap ErrPlanNotIncluded; errors with "insufficient_quota" wrap ErrQuotaExceeded. Unrecognised errors are wrapped as generic Codex generation failures.
func Delete ¶
Delete removes one provider's credentials from auth.json. Unrecognized provider names are silently ignored (idempotent). Supported values: "openai", "anthropic".
func ExtractAccountID ¶
ExtractAccountID returns the account identifier embedded in an OpenAI ID token. It tries four locations in order and returns the first non-empty value found:
- Top-level `chatgpt_account_id` — present on standard consumer accounts.
- `https://api.openai.com/auth.chatgpt_account_id` — custom claim namespace used by enterprise SSO accounts.
- `https://api.openai.com/auth.organization_id` — fallback within the same auth namespace when chatgpt_account_id is absent.
- `organizations[0].id` — last resort for accounts linked to an org.
Returns "" if the token is unparseable, if none of the four claim paths are populated, or if the input is malformed in any way. This function does NOT verify the JWT signature — it is a passive consumer of OpenAI's claim. Safe to call with attacker-controlled input: no crypto, no network, and it never panics. It always returns "" on any decode or parse error.
Segment acceptance: the function accepts any token with at least two dot-separated segments and treats segment [1] as the base64url payload. JWE tokens (4–5 segments) and 2-segment tokens will decode successfully but yield empty claims because their second segment is either encrypted or missing expected fields — both cases return "" cleanly.
func GenerateState ¶
GenerateState returns a 32-byte cryptographically random nonce encoded as base64url with no padding. Used as the OAuth2 state parameter to prevent CSRF (RFC 6749 §10.12).
func GenerateVerifier ¶
GenerateVerifier returns a 43-character PKCE code verifier sampled from the URL-unreserved alphabet (RFC 7636 §4.1) using rejection-sampling on crypto/rand bytes to eliminate modulo bias. Entropy: 43 × log2(66) ≈ 260 bits, exceeding RFC 7636 §7.1's 128-bit recommendation. The rejection threshold is (256/alphabetN)*alphabetN so each accepted byte maps to exactly one of the 66 alphabet positions with uniform probability.
func HTTPClient
deprecated
HTTPClient returns an *http.Client pre-configured to route requests through the Codex Responses API with automatic OAuth bearer-token injection and refresh. The transport is seeded from the OpenAI credentials currently on disk at the time of the call. Subsequent cross-process token rotations are detected lazily via the invalid_grant recovery path in codexTransport.
ctx is reserved for future use (e.g. tracing the credential load). All per-request context propagation happens via the individual request's context.
Returns ErrNotLoggedIn (sentinel) if no credentials are stored. Callers should errors.Is against it and prompt the user to run Login.
Deprecated: use NewClient(Options{AppName: "advisor"}).HTTPClient instead.
func IsCodexAllowed ¶
IsCodexAllowed reports whether model is permitted for use with the Codex subscription endpoint. Admission follows two paths:
Explicit allow-list — models licensed for Codex regardless of their version order in the `gpt-<N>.<M>` space (e.g. gpt-5.3-codex, which is below the regex cutoff but ships with Codex access). Sourced from opencode codex.ts §CODEX_MODELS; see .claude/docs/codex-auth/06-models-and-errors.md.
Version regex — any model ID matching ^gpt-<major>.<minor> where the integer pair (major, minor) is strictly greater than (5, 4). Minor versions are compared as integers, not as floats: gpt-5.10 has minor=10 > 4, so it is allowed; a float parse of "5.10" would give 5.1 < 5.4 and incorrectly exclude it. The regex has no end anchor, so a trailing patch component (e.g. gpt-5.5.0) is ignored — only the first major.minor pair is examined.
The caller is responsible for normalizing model identifiers before calling this function. It is case-sensitive and does not strip provider prefixes (e.g. "openai/gpt-5.5" would not match).
func Logout
deprecated
Logout revokes the stored refresh token (RFC 7009 best-effort) and then deletes the on-disk OpenAI credentials. Network errors during revocation are logged to logoutStderr but do not prevent the local delete. Idempotent: returns nil when no credentials are stored.
Deprecated: use NewClient(Options{AppName: "advisor"}).Logout instead.
func Save ¶
Save persists af to auth.json using the atomic write protocol: MkdirAll → flock(.lock) → re-read → merge → CreateTemp → Write+Sync → Chmod 0600 → Rename → fsync dir → Chmod dir 0700 → release flock.
Fields in af that are nil are not written; existing values for those providers are preserved from the on-disk file (merge-don't-clobber).
func StartCallbackServer ¶
func StartCallbackServer(ctx context.Context, state string) (codeCh <-chan string, errCh <-chan error, shutdown func(), err error)
StartCallbackServer binds loopback listeners on OAuthPort (1455) for both IPv4 (127.0.0.1) and IPv6 ([::1]) and serves a /auth/callback handler.
Both listeners are bound synchronously before the function returns — callers may open the browser immediately after a nil err return. If either bind fails with EADDRINUSE, *PortInUseError is returned and no goroutines are started. If IPv6 is unavailable for reasons other than EADDRINUSE, only IPv4 is used.
The server shuts down automatically when ctx is cancelled or times out. The returned shutdown func may also be called directly (e.g. via defer) to close the server; subsequent calls to shutdown are no-ops.
Types ¶
type AuthError ¶
AuthError represents an RFC 6749 error response from the token endpoint. The Code field contains the OAuth error code string (e.g. "invalid_grant", "invalid_client") as defined in RFC 6749 §5.2. Callers use errors.As to inspect Code and map it to the appropriate core.ErrType.
type AuthFile ¶
type AuthFile struct {
// OpenAI is nil if no OpenAI creds are stored. When non-nil, IDToken is
// always "" — the ID token is consumed once by ExtractAccountID and is
// never persisted.
OpenAI *Credentials
Anthropic *json.RawMessage // raw bytes; never inspected by this package
}
AuthFile is the caller-facing view of auth.json.
On POSIX, auth.json is created with mode 0600 and its parent directory with mode 0700. On Windows, file access is governed by inherited ACLs from %LocalAppData%; Chmod is a best-effort approximation only.
func Load ¶
Load reads auth.json and returns its contents. A missing file is not an error; the returned AuthFile has nil fields in that case.
Load acquires a shared (read) flock for cross-process safety, but does NOT hold the lock after returning. Callers performing a read-modify-write (e.g. load → refresh tokens → save) should be aware that another process may persist a rotation in between; the Save call's "re-read under lock + merge" path protects against clobbering the *other* provider's entry but does NOT detect that the OpenAI refresh token the caller is about to overwrite was already rotated by a sibling process. For concurrent-safe refresh, route through a single goroutine / singleflight per process.
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client authenticates a single Codex consumer with its own credential namespace and test seams. ListModels calls made through one Client are serialized; distinct Client values and processes are not coalesced.
func NewClient ¶
NewClient returns a Client configured from opts.
Example ¶
package main
import (
"bytes"
"context"
"errors"
"log"
"net/http"
codexauth "github.com/mattsp1290/codex-auth-go"
)
func main() {
if false {
ctx := context.Background()
auth := codexauth.NewClient(codexauth.Options{AppName: "yourapp"})
status, err := auth.Status(ctx)
if err != nil {
log.Fatal(err)
}
if !status.LoggedIn {
if _, err := auth.Login(ctx, false); err != nil {
log.Fatal(err)
}
}
httpClient, err := auth.HTTPClient(ctx)
if errors.Is(err, codexauth.ErrNotLoggedIn) {
log.Fatal("not logged in")
}
if err != nil {
log.Fatal(err)
}
body := bytes.NewBufferString(`{"model":"gpt-5.5","input":"hello"}`)
req, err := http.NewRequestWithContext(ctx, http.MethodPost, codexauth.CodexEndpoint, body)
if err != nil {
log.Fatal(err)
}
req.Header.Set("Content-Type", "application/json")
_ = httpClient
_ = req
}
}
Output:
func (*Client) HTTPClient ¶
HTTPClient returns an *http.Client pre-configured for this client's stored Codex credentials.
func (*Client) ListModels ¶ added in v0.4.0
ListModels fetches the current picker-visible model catalog for this client's authenticated account. clientVersion is an opaque, non-secret compatibility value supplied by the caller and is passed through unchanged. The result is stable-sorted by ascending server priority; reasoning options retain their server order. The package does not cache results.
Calls through one Client are serialized so stale rotating refresh tokens are not used concurrently. Distinct clients and processes are not coalesced. Cancellation during a stale-token refresh may return only after the existing detached refresh persistence step finishes, but no catalog request is sent afterward.
Example ¶
package main
import (
"context"
"errors"
"log"
codexauth "github.com/mattsp1290/codex-auth-go"
)
func main() {
if false {
ctx := context.Background()
auth := codexauth.NewClient(codexauth.Options{AppName: "yourapp"})
models, err := auth.ListModels(ctx, "your-catalog-compatibility-value")
if errors.Is(err, codexauth.ErrNotLoggedIn) {
log.Fatal("not logged in")
}
if err != nil {
log.Fatal(err)
}
for _, model := range models {
_ = model.Slug
_ = model.SupportedReasoningEfforts
}
}
}
Output:
func (*Client) LoginBrowser ¶
func (c *Client) LoginBrowser(ctx context.Context) (Credentials, error)
LoginBrowser implements the browser-based OAuth2 + PKCE authorization flow for this client.
func (*Client) LoginDevice ¶
func (c *Client) LoginDevice(ctx context.Context) (Credentials, error)
LoginDevice implements OpenAI's headless device-authorization flow for this client.
func (*Client) Logout ¶
Logout revokes this client's stored refresh token and deletes local credentials.
type Credentials ¶
type Credentials struct {
Access string `json:"-"`
Refresh string `json:"-"`
IDToken string `json:"-"`
Expires int64 `json:"-"` // absolute epoch milliseconds when Access expires
AccountID string `json:"-"` // populated by caller via ExtractAccountID, not here
}
Credentials is part of the public v0.1.0 API surface. It holds the OAuth token set returned after a successful authorization-code exchange or token refresh.
Expires is an absolute Unix epoch in milliseconds — not a relative duration — so callers can compare it directly against time.Now().UnixMilli().
AccountID is not populated by ExchangeCode or RefreshToken; callers should invoke ExtractAccountID(creds.IDToken) separately and store the result before the ID token is discarded.
func ExchangeCode ¶
func ExchangeCode(ctx context.Context, code, verifier, redirectURI string) (Credentials, error)
ExchangeCode trades an authorization code (plus PKCE code verifier) for a token set. The redirectURI must exactly match the redirect_uri sent during the /authorize request; a mismatch will cause the server to reject the exchange with invalid_grant.
Returns *AuthError if the server responds with an OAuth error. The Credentials.AccountID field is always empty; populate it via ExtractAccountID after calling this function.
func Login
deprecated
func Login(ctx context.Context, forceDevice bool) (Credentials, error)
Login initiates an OAuth flow and returns fresh credentials.
If forceDevice is true, the device-authorization flow is used regardless of browser availability. Otherwise, Login probes for a browser launcher via browserAvailableCheck: any non-nil return causes Login to fall back to the device flow. When a browser is available, the PKCE browser flow is used.
Deprecated: use NewClient(Options{AppName: "advisor"}).Login instead.
func LoginBrowser
deprecated
func LoginBrowser(ctx context.Context) (Credentials, error)
LoginBrowser implements the browser-based OAuth2 + PKCE authorization flow:
- Generates a PKCE verifier, S256 challenge, and CSRF state nonce.
- Starts the local callback server (MUST happen before opening the browser).
- Opens the browser to the authorize URL; if no browser is available, prints the URL to stderr for manual copy-paste.
- Waits up to browserLoginTimeout for the OAuth callback.
- Exchanges the authorization code for tokens.
- Extracts the account ID and persists credentials.
If port OAuthPort (1455) is already in use, LoginBrowser returns *PortInUseError without opening the browser — the trip-wire invariant in the test suite enforces that openBrowserFn is never called on an EADDRINUSE failure.
Deprecated: use NewClient(Options{AppName: "advisor"}).LoginBrowser instead.
func LoginDevice
deprecated
func LoginDevice(ctx context.Context) (Credentials, error)
LoginDevice implements OpenAI's headless device-authorization flow for SSH / CI environments. The flow:
- Requests a user_code from the device init endpoint.
- Validates user_code charset to guard against terminal injection.
- Prompts the user to open the device URL and enter the code.
- Polls the token endpoint at (interval+3)s until authorized or expired.
- Exchanges the authorization_code for OAuth tokens.
- Extracts the account ID and persists credentials to disk.
This is NOT RFC 8628 — OpenAI uses custom /api/accounts/deviceauth/ endpoints and returns an authorization_code that must be exchanged at /oauth/token. See .claude/docs/codex-auth/03-device-flow.md.
Deprecated: use NewClient(Options{AppName: "advisor"}).LoginDevice instead.
func RefreshToken ¶
func RefreshToken(ctx context.Context, refreshTok string) (Credentials, error)
RefreshToken exchanges a refresh token for a new token set. The refresh token rotates on every successful call — the returned Credentials.Refresh must be persisted immediately; the old token is invalidated by the server.
Returns *AuthError if the server responds with an OAuth error. The most common error is "invalid_grant" (refresh token revoked, expired after 90 days of inactivity, or user signed out from all sessions).
func (Credentials) LogValue ¶
func (c Credentials) LogValue() slog.Value
LogValue implements slog.LogValuer. It returns a redacted representation so that slog.Info("creds", "c", creds) never emits token values into logs.
func (Credentials) String ¶
func (c Credentials) String() string
String implements fmt.Stringer. Returns a redacted sentinel so that fmt.Sprintf("%v", creds) and log lines using %v cannot leak token values.
type DeviceError ¶
type DeviceError struct {
Code string
Message string
Err error // underlying error, if any; see Unwrap
}
DeviceError is a typed error returned by LoginDevice for flow-level failures: invalid user_code charset, fatal poll response, or expiry. Err holds an optional underlying error so errors.Is/As can traverse the chain.
func (*DeviceError) Error ¶
func (e *DeviceError) Error() string
func (*DeviceError) Unwrap ¶
func (e *DeviceError) Unwrap() error
Unwrap returns the underlying error so errors.Is and errors.As can traverse the chain (e.g. errors.Is(de, context.Canceled) works through a *DeviceError).
type ModelCatalogEntry ¶ added in v0.4.0
type ModelCatalogEntry struct {
Slug string
DisplayName string
Description *string
Priority int
DefaultReasoningEffort *string
SupportedReasoningEfforts []ReasoningEffortOption
}
ModelCatalogEntry describes one picker-visible model available to the authenticated ChatGPT account.
type ModelCatalogHTTPError ¶ added in v0.4.0
type ModelCatalogHTTPError struct {
StatusCode int
}
ModelCatalogHTTPError reports a non-success response from the model catalog. It intentionally exposes only the status code, never the response body.
func (*ModelCatalogHTTPError) Error ¶ added in v0.4.0
func (e *ModelCatalogHTTPError) Error() string
type Options ¶
type Options struct {
// AppName selects the on-disk credential directory. An empty AppName
// defaults to "codex" for explicit clients.
AppName string
// CallbackPort selects the local OAuth callback port. Zero defaults to
// OAuthPort.
CallbackPort int
// Logger receives structured diagnostics. Nil defaults to slog.Default().
Logger *slog.Logger
// DevicePrompt is called during device login after a safe user_code is
// received and before polling begins. Nil preserves the default stderr
// prompt.
DevicePrompt func(verificationURI, userCode string) error
// Endpoint overrides the Responses-API URL that the transport rewrites every
// request to. Empty preserves the default (CodexEndpoint,
// https://chatgpt.com/backend-api/codex/responses). The value is parsed and
// validated lazily in HTTPClient or ListModels (not NewClient): it must be an
// absolute URL with scheme http or https. ListModels derives a sibling models
// route by normalizing trailing slashes and replacing the final path segment
// with "models". As a safety rail, a cleartext http:// endpoint is permitted
// only for loopback hosts (127.0.0.0/8, ::1, localhost) so a bearer token is
// never sent in plaintext to a remote host.
//
// Note: only Scheme, Host, and Path from Endpoint are used. Any query string
// embedded in Endpoint is silently dropped; HTTPClient preserves the caller's
// query string unchanged, while ListModels supplies only its client_version
// query. ListModels also drops any Endpoint fragment.
//
// Redirect caveat: when Endpoint uses cleartext http:// (loopback only), the
// server must respond directly (e.g. 200 with the SSE body) and must NOT issue
// a 3xx redirect. The client's redirect policy hard-refuses any non-https
// redirect hop and returns "codexauth: refusing non-https redirect". This is
// intentional defense-in-depth, not a bug — design your test fake accordingly.
Endpoint string
// CredentialPath overrides the on-disk auth.json location. Empty preserves the
// default, os.UserConfigDir()/<AppName>/auth.json (where <AppName> defaults to
// "codex" for explicit NewClient callers). When set, all credential reads and
// writes for this client target the given path — useful for staging a fixture
// credential file in tests without touching HOME/XDG.
//
// WARNING: point this at a file inside a directory you own EXCLUSIVELY. On any
// write (Save/Logout/refresh) the PARENT DIRECTORY of this path is MkdirAll'd
// AND its permissions are unconditionally overwritten to 0700 — even if the
// directory already existed. Pointing CredentialPath at a file in a shared
// directory (e.g. /tmp/auth.json, $HOME/auth.json) will re-permission that
// directory to owner-only on first write. Use t.TempDir() in tests.
// Reads do not mutate anything.
CredentialPath string
}
Options configures a Client.
type PortInUseError ¶
PortInUseError is returned by StartCallbackServer when port OAuthPort (1455) is already bound on either loopback address. The caller should surface this to the user; the fix is to stop the other process holding the port.
func (*PortInUseError) Error ¶
func (e *PortInUseError) Error() string
func (*PortInUseError) Unwrap ¶
func (e *PortInUseError) Unwrap() error
type ReasoningEffortOption ¶ added in v0.4.0
ReasoningEffortOption describes one server-supported reasoning setting. Effort is intentionally an open string so new server values remain usable.