package codex import ( "encoding/base64" "encoding/json" "fmt" "strings" "time") // JWTClaims represents the claims section of a JWT tokentype JWTClaims struct { AtHash string `json:"at_hash"` Aud []string `json:"aud"` AuthProvider string `json:"auth_provider"` AuthTime int `json:"auth_time"` Email string `json:"email"` EmailVerified bool `json:"email_verified"` Exp int `json:"exp"` CodexAuthInfo CodexAuthInfo `json:"https://api.openai.com/auth"` Iat int `json:"iat"` Iss string `json:"iss"` Jti string `json:"jti"` Rat int `json:"rat"` Sid string `json:"sid"` Sub string `json:"sub"`}type Organizations struct { ID string `json:"id"` IsDefault bool `json:"is_default"` Role string `json:"role"` Title string `json:"title"`}type CodexAuthInfo struct { ChatgptAccountID string `json:"chatgpt_account_id"` ChatgptPlanType string `json:"chatgpt_plan_type"` ChatgptSubscriptionActiveStart any `json:"chatgpt_subscription_active_start"` ChatgptSubscriptionActiveUntil any `json:"chatgpt_subscription_active_until"` ChatgptSubscriptionLastChecked time.Time `json:"chatgpt_subscription_last_checked"` ChatgptUserID string `json:"chatgpt_user_id"` Groups []any `json:"groups"` Organizations []Organizations `json:"organizations"` UserID string `json:"user_id"`} // ParseJWTToken parses a JWT token and extracts the claims without verification// This is used for extracting user information from ID tokensfunc ParseJWTToken(token string) (*JWTClaims, error) { parts := strings.Split(token, ".") if len(parts) != 3 { return nil, fmt.Errorf("invalid JWT token format: expected 3 parts, got %d", len(parts)) } // Decode the claims (payload) part claimsData, err := base64URLDecode(parts[1]) if err != nil { return nil, fmt.Errorf("failed to decode JWT claims: %w", err) } var claims JWTClaims if err = json.Unmarshal(claimsData, &claims); err != nil { return nil, fmt.Errorf("failed to unmarshal JWT claims: %w", err) } return &claims, nil} // base64URLDecode decodes a base64 URL-encoded string with proper paddingfunc base64URLDecode(data string) ([]byte, error) { // Add padding if necessary switch len(data) % 4 { case 2: data += "==" case 3: data += "=" } return base64.URLEncoding.DecodeString(data)} // GetUserEmail extracts the user email from JWT claimsfunc (c *JWTClaims) GetUserEmail() string { return c.Email} // GetAccountID extracts the user ID from JWT claims (subject)func (c *JWTClaims) GetAccountID() string { return c.CodexAuthInfo.ChatgptAccountID}
package codex
import (
"encoding/base64"
"encoding/json"
"fmt"
"strings"
"time"
)
// JWTClaims represents the claims section of a JWT token
type JWTClaims struct {
AtHash string `json:"at_hash"`
Aud []string `json:"aud"`
AuthProvider string `json:"auth_provider"`
AuthTime int `json:"auth_time"`
Email string `json:"email"`
EmailVerified bool `json:"email_verified"`
Exp int `json:"exp"`
CodexAuthInfo CodexAuthInfo `json:"https://api.openai.com/auth"`
Iat int `json:"iat"`
Iss string `json:"iss"`
Jti string `json:"jti"`
Rat int `json:"rat"`
Sid string `json:"sid"`
Sub string `json:"sub"`
}
type Organizations struct {
ID string `json:"id"`
IsDefault bool `json:"is_default"`
Role string `json:"role"`
Title string `json:"title"`
}
type CodexAuthInfo struct {
ChatgptAccountID string `json:"chatgpt_account_id"`
ChatgptPlanType string `json:"chatgpt_plan_type"`
ChatgptSubscriptionActiveStart any `json:"chatgpt_subscription_active_start"`
ChatgptSubscriptionActiveUntil any `json:"chatgpt_subscription_active_until"`
ChatgptSubscriptionLastChecked time.Time `json:"chatgpt_subscription_last_checked"`
ChatgptUserID string `json:"chatgpt_user_id"`
Groups []any `json:"groups"`
Organizations []Organizations `json:"organizations"`
UserID string `json:"user_id"`
}
// ParseJWTToken parses a JWT token and extracts the claims without verification
// This is used for extracting user information from ID tokens
func ParseJWTToken(token string) (*JWTClaims, error) {
parts := strings.Split(token, ".")
if len(parts) != 3 {
return nil, fmt.Errorf("invalid JWT token format: expected 3 parts, got %d", len(parts))
}
// Decode the claims (payload) part
claimsData, err := base64URLDecode(parts[1])
if err != nil {
return nil, fmt.Errorf("failed to decode JWT claims: %w", err)
}
var claims JWTClaims
if err = json.Unmarshal(claimsData, &claims); err != nil {
return nil, fmt.Errorf("failed to unmarshal JWT claims: %w", err)
}
return &claims, nil
}
// base64URLDecode decodes a base64 URL-encoded string with proper padding
func base64URLDecode(data string) ([]byte, error) {
// Add padding if necessary
switch len(data) % 4 {
case 2:
data += "=="
case 3:
data += "="
}
return base64.URLEncoding.DecodeString(data)
}
// GetUserEmail extracts the user email from JWT claims
func (c *JWTClaims) GetUserEmail() string {
return c.Email
}
// GetAccountID extracts the user ID from JWT claims (subject)
func (c *JWTClaims) GetAccountID() string {
return c.CodexAuthInfo.ChatgptAccountID
}