codexauth

package
v0.64.3 Latest Latest
Warning

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

Go to latest
Published: May 21, 2026 License: MIT Imports: 20 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrRefreshTokenReuse = errors.New("refresh token unknown or revoked")

ErrRefreshTokenReuse is returned by RotateRefreshToken when the presented token is unknown OR has already been revoked. Callers (the /oauth/token refresh handler) should map this to a 401 with OAuth error `refresh_token_expired` or `refresh_token_reused`.

Functions

func BuildAccessToken

func BuildAccessToken(key *rsa.PrivateKey, kid string, c IDTokenClaims) (string, error)

BuildAccessToken mints the access_token as an RS256 JWT carrying just `{iss, sub, iat, exp}`. Codex never validates the signature (it treats access_token as an opaque bearer), but it *does* parse `exp` to drive proactive refresh (login/src/auth/manager.rs:1793-1812 — is_stale_for_proactive_refresh calls parse_jwt_expiration on access_token). Minting the access_token as a JWT means codex refreshes cleanly at the real expiry instead of waiting for a 401 retry.

func BuildAgentIdentityJWT

func BuildAgentIdentityJWT(key *rsa.PrivateKey, kid string, c AgentIdentityClaims) (string, error)

BuildAgentIdentityJWT returns an RS256 JWT whose claims pass codex's strict aud="codex-app-server" + iss=".../agent-identity" check.

func BuildIDToken

func BuildIDToken(key *rsa.PrivateKey, kid string, c IDTokenClaims) (string, error)

BuildIDToken returns a signed RS256 JWT with the OpenAI-nested claim that codex's `compose_success_url` and `jwt_auth_claims` paths expect (login/src/server.rs:821-907).

func GenerateEd25519Key

func GenerateEd25519Key() (privatePKCS8 []byte, public []byte, err error)

GenerateEd25519Key produces an Ed25519 keypair used per-agent for AgentAssertion signing. PrivatePKCS8 is stored on the client (inside the Agent Identity JWT's agent_private_key claim); the public key stays server-side for verification.

func HashToken

func HashToken(raw string) []byte

HashToken returns sha256(raw) suitable for DB primary key. Tokens are never stored plaintext.

func LoadRSAPrivate

func LoadRSAPrivate(pkcs8 []byte) (*rsa.PrivateKey, error)

LoadRSAPrivate parses a PKCS#8 DER blob (as stored in codex_jwks_keys.private_pkcs8) back into an *rsa.PrivateKey for signing.

Types

type AgentIdentity

type AgentIdentity struct {
	AgentRuntimeID string
	UserID         string
	PublicKey      []byte
	JWTSignedWith  string
	IssuedAt       time.Time
	ExpiresAt      time.Time
}

type AgentIdentityClaims

type AgentIdentityClaims struct {
	AgentRuntimeID       string
	AgentPrivateKeyPKCS8 []byte
	AccountID            string
	ChatgptUserID        string
	Email                string
	PlanType             string
	ExpiresAt            time.Time
}

AgentIdentityClaims is the JWT codex's exec-server --remote --use-agent-identity-auth requires (agent-identity/src/lib.rs:65-78).

type AgentTask

type AgentTask struct {
	TaskID         string
	AgentRuntimeID string
	UserID         string
	IssuedAt       time.Time
	ExpiresAt      time.Time
}

type DeviceCode

type DeviceCode struct {
	DeviceAuthID      string
	UserCode          string
	CodeChallenge     string
	CodeVerifier      string
	AuthorizationCode string
	Status            string
	UserID            string
	ExpiresAt         time.Time
	ApprovedAt        *time.Time
}

type IDTokenClaims

type IDTokenClaims struct {
	Issuer    string
	Subject   string
	Email     string
	ExpiresAt time.Time
}

IDTokenClaims is the subset of fields we populate for the OpenAI-shaped id_token. Codex never verifies the signature, but it base64-decodes the payload and looks for the nested OpenAI claim.

type JwksKey

type JwksKey struct {
	Kid          string
	PublicN      string
	PublicE      string
	PrivatePKCS8 []byte
	Active       bool
}

func EnsureActiveKey

func EnsureActiveKey(ctx context.Context, s *Store) (*JwksKey, error)

EnsureActiveKey returns the active JWKS key, generating a fresh one and inserting it into the store if none exists. Idempotent — safe to call at every server startup.

type MintAgentIdentityArgs

type MintAgentIdentityArgs struct {
	AgentRuntimeID string // == exe_id
	UserID         string
	Email          string
}

MintAgentIdentityArgs is the input shape used by the UI's "Add connector" path and the test bench.

type MintAgentIdentityResult

type MintAgentIdentityResult struct {
	JWT string
	// contains filtered or unexported fields
}

MintAgentIdentityResult is what the UI shows the user (JWT) and what tests use (privKey) to assert downstream signature checks pass.

type PkceRequest

type PkceRequest struct {
	Code          string
	CodeChallenge string
	State         string
	UserID        string
	ExpiresAt     time.Time
}

type RSAKeyPair

type RSAKeyPair struct {
	PrivateKey   *rsa.PrivateKey
	PrivatePKCS8 []byte
	PublicN      string
	PublicE      string
}

RSAKeyPair is an RSA-2048 keypair ready for JWKS exposure (public) and JWT signing (private). PublicN/PublicE are base64url-no-pad encoded for direct JWKS serialization; PrivatePKCS8 is the DER blob stored encrypted at rest.

func GenerateRSAKey

func GenerateRSAKey() (kid string, kp *RSAKeyPair, err error)

GenerateRSAKey mints a fresh RSA-2048 keypair and a deterministic kid derived from the public modulus prefix. kid stability matters because it's embedded in JWT headers and used to look up the verification key in JWKS; a random kid forces full JWKS scans.

type Server

type Server struct {
	Store            *Store
	IssuerURL        string          // e.g. "https://agent.cs.ac.cn/codex-auth"
	SigningKey       *rsa.PrivateKey // active RSA key for id_token + Agent Identity JWT
	SigningKid       string
	SessionResolve   SessionResolver
	LoginRedirectURL string // where /oauth/authorize sends unauth users
}

Server is the user-facing codex-auth HTTP surface (PKCE / device flow / JWKS / agent-identity), all mounted under a single chi subrouter.

func (*Server) HandleValidate

func (s *Server) HandleValidate(w http.ResponseWriter, r *http.Request)

HandleValidate is the internal endpoint codex-exec-gateway calls over X-Internal-Secret to verify a Bearer / AgentAssertion token. Returns 200 with {user_id} or 401 with {error}.

func (*Server) MintAgentIdentity

func (s *Server) MintAgentIdentity(ctx context.Context, args MintAgentIdentityArgs) (*MintAgentIdentityResult, error)

MintAgentIdentity generates an Ed25519 keypair for the new agent, signs the Agent Identity JWT with the active RSA key, and persists (public key, jwt_signed_with) so subsequent AgentAssertion signatures can be verified.

func (*Server) Mount

func (s *Server) Mount(r chi.Router)

Mount registers all codex-auth routes onto r. Routes are mounted without a prefix; the caller decides where this subtree lives (typically /codex-auth/* on agentserver's outermost router).

type SessionResolver

type SessionResolver func(r *http.Request) string

SessionResolver returns the user_id for the request's session cookie, or empty string if unauthenticated. agentserver supplies its existing session middleware here.

type Store

type Store struct {
	// contains filtered or unexported fields
}

Store is a thin DB facade over all codex_* tables. Each method takes a context and returns a typed value or error; no business logic lives here (compose in pkce.go, agent_identity.go, etc.).

func NewStore

func NewStore(d *db.DB) *Store

func (*Store) ApproveDeviceCode

func (s *Store) ApproveDeviceCode(ctx context.Context, userCode, userID string) error

func (*Store) ConsumePkceRequest

func (s *Store) ConsumePkceRequest(ctx context.Context, code string) (*PkceRequest, error)

ConsumePkceRequest atomically deletes and returns the row. Returns nil if the code is missing or expired.

func (*Store) ExchangeDeviceCode

func (s *Store) ExchangeDeviceCode(ctx context.Context, deviceAuthID, userCode string) (*DeviceCode, error)

ExchangeDeviceCode atomically returns the row and marks it 'exchanged'. Only approved rows are returned; subsequent calls return nil.

func (*Store) GetActiveJwksKey

func (s *Store) GetActiveJwksKey(ctx context.Context) (*JwksKey, error)

func (*Store) GetAgentIdentity

func (s *Store) GetAgentIdentity(ctx context.Context, rid string) (*AgentIdentity, error)

func (*Store) GetAgentTask

func (s *Store) GetAgentTask(ctx context.Context, taskID string) (*AgentTask, error)

func (*Store) GetDeviceCodeByUserCode

func (s *Store) GetDeviceCodeByUserCode(ctx context.Context, userCode string) (*DeviceCode, error)

func (*Store) InsertAccessToken

func (s *Store) InsertAccessToken(ctx context.Context, tokenHash []byte, userID string, expiresAt time.Time) error

func (*Store) InsertAgentIdentity

func (s *Store) InsertAgentIdentity(ctx context.Context, a AgentIdentity) error

func (*Store) InsertAgentTask

func (s *Store) InsertAgentTask(ctx context.Context, taskID, rid, userID string, expiresAt time.Time) error

func (*Store) InsertDeviceCode

func (s *Store) InsertDeviceCode(ctx context.Context, dc DeviceCode) error

func (*Store) InsertJwksKey

func (s *Store) InsertJwksKey(ctx context.Context, kid string, kp *RSAKeyPair, active bool) error

func (*Store) InsertPkceRequest

func (s *Store) InsertPkceRequest(ctx context.Context, r PkceRequest) error

func (*Store) InsertRefreshToken

func (s *Store) InsertRefreshToken(ctx context.Context, tokenHash []byte, familyID, userID string, expiresAt time.Time) error

func (*Store) ListAllJwksKeys

func (s *Store) ListAllJwksKeys(ctx context.Context) ([]JwksKey, error)

func (*Store) LookupAccessToken

func (s *Store) LookupAccessToken(ctx context.Context, rawToken string) (string, error)

LookupAccessToken returns the user_id if the token is valid (exists, not expired, not revoked); empty string otherwise.

func (*Store) RotateRefreshToken

func (s *Store) RotateRefreshToken(ctx context.Context, oldRaw string, newHash []byte, newExpiry time.Time) (string, error)

RotateRefreshToken revokes the old refresh token and inserts a new one in the same family. Returns the user_id; errors if the old token is missing or already revoked.

Jump to

Keyboard shortcuts

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