ChappieAuthState value and an optional ChappieAccountInfo struct that contains the user’s email, plan, and account identifiers. Chappie also refreshes expired tokens automatically before every request, so you don’t need to manage token lifetimes yourself.
How authentication works
User taps sign in
Your app calls
startDeviceCodeSignIn() — or uses the ChappieSignIn button that calls it for you. The SDK requests a short-lived device code from OpenAI.User approves in a browser
The user opens the verification URL (automatically or manually), signs in with their ChatGPT account, and pastes the device code. Chappie polls in the background until the code is approved.
Credentials stored in Keychain
When polling succeeds, the SDK writes the access and refresh tokens to Keychain using the accessibility and account settings you configured. Your app never sees the raw tokens.
Auth state published to your UI
ChappieAuthSession.state transitions to .signedIn and accountInfo is populated. Subsequent app launches restore the session from Keychain automatically.Creating an auth session
Create a singleChappieAuthSession as a @StateObject in the view that owns your sign-in flow. Chappie reads the Keychain at init time, so the session is already populated if the user signed in during a previous launch.
ChappieConfiguration to customise which Keychain slot is used, or to support multiple accounts. See Multi-Account for details.
Observing auth state
ChappieAuthSession is an ObservableObject with four published properties:
| Property | Type | Description |
|---|---|---|
state | ChappieAuthState | The current sign-in lifecycle stage |
deviceLinkState | ChappieDeviceLinkState | Fine-grained progress through the device-code exchange |
accountInfo | ChappieAccountInfo? | Email, plan, userID, and accountID — populated once signed in |
lastError | ChappieAuthError? | The most recent auth failure, or nil if none |
state in your SwiftUI views to switch between signed-out and signed-in UI:
ChappieAuthState values
| Case | Meaning |
|---|---|
.signedOut | No credential is stored; the user has not signed in |
.signingIn | Sign-in has started; the device code is being requested |
.awaitingDeviceCode(userCode:verificationURL:) | The device code is ready; waiting for the user to approve it in a browser |
.signedIn(expiresAt:) | The user is signed in; expiresAt is the credential expiry date, or nil if unknown |
.reauthenticationRequired | The stored refresh token is invalid or missing; the user must sign in again |
.failed(String) | An unrecoverable error occurred; the associated string is a human-readable message |
Account info
After a successful sign-in,authSession.accountInfo is a ChappieAccountInfo value with the following fields:
| Field | Type | Description |
|---|---|---|
email | String? | The user’s ChatGPT email address |
userID | String? | The ChatGPT user identifier |
accountID | String? | The ChatGPT account (organisation) identifier |
plan | ChappiePlan? | The user’s current plan, with a human-readable displayName |
isFedRAMPAccount | Bool | true for FedRAMP-compliant accounts |
Signing out
CallsignOut() to clear the stored Keychain credential and reset state to .signedOut. Any in-progress sign-in polling task is cancelled automatically.
Manual token refresh
Chappie refreshes credentials automatically before requests. If you need to force a refresh — for example, after the user upgrades their plan — callrefreshAuth():
refreshAuth() transitions the session to .reauthenticationRequired and throws a ChappieAuthError. Prompt the user to sign in again in that case.
Error reference
ChappieAuthError cases
ChappieAuthError cases
| Case | When it occurs |
|---|---|
.expiredDeviceCode | The user did not approve the device code before it expired |
.cancelledSignIn | Sign-in was cancelled programmatically or by the user |
.networkFailure(String) | A network request failed; the associated string is the underlying error message |
.pollingTimeout | The SDK stopped polling before the device code was approved |
.callbackTimeout | The sign-in callback did not arrive in time |
.authorizationDenied(String) | OpenAI denied the authorisation request |
.tokenExchangeFailed(statusCode:body:) | The token exchange returned an HTTP error; inspect statusCode and body |
.missingRefreshToken | No refresh token is stored; the user must sign in from scratch |
.secureRandomFailed(statusCode:) | Secure random number generation failed at the OS level |
.invalidResponse | The sign-in response could not be parsed |
.unknown(String) | An unexpected error occurred; the associated string contains details |
requiresReauthentication is true on a ChappieAuthError (currently .missingRefreshToken and certain token-exchange failures), the SDK automatically signs out and transitions to .reauthenticationRequired. All other errors leave existing credentials intact so a retry is possible.Your app never receives raw access or refresh tokens through Chappie’s public API.
ChappieAccountInfo exposes only identity and plan metadata derived from the stored credential.