Authentication
Configure the application
Section titled “Configure the application”The project owner maintains Sodapop’s dedicated GitHub OAuth application with device authorization enabled. Keep the existing registration, public Client ID, and grants rather than creating a replacement application. Its public display name is Sodapop and its homepage is https://sodapop.sh. A development build reads SODAPOP_GITHUB_CLIENT_ID; a distribution build may include the same public identifier at build time.
Use the GitHub OAuth application settings and device-flow documentation. A distributed CLI must not contain a client secret or private key. Sodapop does not borrow the GitHub CLI or Copilot CLI’s client identity, token, or login session.
For the existing application’s badge, use the Sodapop OAuth logo and set Badge background color to #09090B. The square image includes room for GitHub’s circular crop. Branding changes must preserve the existing Client ID, grants, callback URL, and device-flow setting; do not register a replacement application.
For local Make-based development, copy .sodapop.env.example to the ignored .sodapop.env and set only SODAPOP_GITHUB_CLIENT_ID. Direct script invocations and the installed executable do not load that file; export the variable explicitly or use a build with the public ID linked in. Release-candidate builds in the Sodapop repository read the same public ID from the Actions variable SODAPOP_GITHUB_CLIENT_ID. No token or client secret belongs in this setting.
Before release, prove that a user token issued to this application can list Copilot models and complete a real coding conversation under an eligible account and its organization policies. Generic GitHub sign-in is not proof of Copilot access. The Copilot SDK OAuth guide describes passing user tokens to the SDK.
User flow
Section titled “User flow”- Start Sodapop and run
/login. - Choose persistent or explicit session-only sign-in.
- Sodapop requests device authorization and displays the verification code/link.
- Authorize the Sodapop application in the browser; the terminal remains in Sodapop.
- Sodapop obtains the user identity and connects to Copilot separately.
- Choose an available model and submit a prompt.
Cancellation, denied authorization, expired device codes, unavailable network, and Copilot entitlement failures are distinct outcomes. Sodapop does not silently retry a coding action after authentication changes.
GitHub is signed in, but Copilot is unavailable
Section titled “GitHub is signed in, but Copilot is unavailable”Sodapop retains the GitHub account when Copilot access fails. A background
startup failure stays inline; an access failure following an explicit sign-in
or manual recheck can open a dismissible account dialog. Drafts, the current
transcript, and local commands such as /help, /theme, and /diff remain
available.
Open /login to choose the appropriate recovery action:
- Get Copilot opens the official plans page for an uncertain authorization/access failure. Use the GitHub account shown in Sodapop, which may differ from the account currently signed in to your browser. Review Free eligibility, personal plans, or an organization-provided seat.
- Sign in again renews Sodapop’s GitHub authorization when the credential is rejected or expired. It does not replace the application’s OAuth registration.
- Open Copilot settings is available for quota, rate-limit, and billing conditions. Organization-managed accounts may need administrator assistance.
- Check access again creates a fresh connection for the same account after you resolve the problem. It does not start another OAuth flow, send a probe prompt, or replay an earlier request.
Browser opening and copying the fixed GitHub links require an explicit action. If the platform cannot open a browser, the account dialog keeps the link visible and provides a copy action. Rechecking is manual only, not triggered by browser focus or a polling loop. Stop an unresolved turn with Ctrl+C before reconnecting; the normal cancellation/idle barrier still applies.
The pinned SDK does not expose a definitive subscription-active flag at startup. An empty catalog or generic authorization failure is therefore described as access unavailable, not proof that a subscription is missing. Supported Free access is not rejected for being Free. Policy-disabled models, rejected credentials, quota/billing conditions, and network failures are not presented as a requirement to buy another plan. Fresh model discovery establishes connection/model availability, not a guarantee that every later request will be authorized.
Credential storage
Section titled “Credential storage”Persistent credentials belong in the macOS Keychain, Linux Secret Service, or Windows Credential Manager. If the host has no usable secure store, choose session-only sign-in or cancel; Sodapop does not write token files into its preferences, state directory, project, or default Copilot configuration.
Session-only credentials last for the process. An expired or revoked token requires a secure supported refresh or a new device authorization. Sodapop does not introduce a backend or embed a secret to obtain refresh behavior.
Sign-out deletes Sodapop’s credential and disconnects its engine, but preserves conversation history. Exiting normally does not sign out.
Never include tokens, client secrets, OAuth responses, or private device codes in issues, logs, screenshots, or test fixtures. Only the public Client ID belongs in SODAPOP_GITHUB_CLIENT_ID.
Release qualification
Section titled “Release qualification”The public client registration, minimum scopes, actual Copilot access, and native platform behavior must be qualified with owner-approved test identities. A missing client ID remains a visible blocker rather than a successful mock session. Routine CI uses injected HTTP and credential stores and never requires real account credentials.
Definitively diagnosing a missing subscription requires supported provider evidence for the pinned SDK/runtime. A generic 403 or missing optional metadata is not that evidence. An owner-authorized no-entitlement account can qualify the real service response separately; do not log credentials, private device codes, account identities, or full provider payloads, and do not call a model merely to probe a subscription.