Skip to content

OAuth sign-in

OAuth lets you sign in to your git host through its browser flow — the same handshake the host's own web app uses. No copying tokens by hand, no SSH keys to manage. The host issues a token, hachicode stores it in the Keychain, and clone / push / fetch use it automatically.

Use OAuth when the host offers it and you'd rather sign in once than manage credentials. Use SSH keys or PATs when the host doesn't offer OAuth, or when you specifically prefer a long-lived credential.

Supported providers

ProviderOAuthNotes
GitHub.comAuthorization-code flow (preferred); device flow as fallback
GitHub EnterpriseRequires per-instance OAuth app registration; you provide Client ID
GitLab.comAuthorization-code flow
GitLab (self-hosted)Same as GitLab.com; you provide host
GiteaMost instances support OAuth; you may need Client ID

For hosts not in this list, see SSH keys or use a personal access token via the PAT method tab.

Two flow shapes

Depending on the host and how you've set it up, OAuth runs as one of two flows:

  • Authorization-code flow (preferred). Opens an in-app browser (ASWebAuthenticationSession) at your host's authorize URL. You sign in, approve scopes, the browser redirects back into the app with a one-time code, and the app exchanges that code for an access token. Fast, doesn't ask you to type anything once you're signed in to your host on the device.
  • Device flow (fallback). The app requests a verification code from your host and shows it to you. You open the verification URL on another device (or in any browser), enter the code, and sign in. The app polls until the host confirms. Slower but works when the auth-code flow can't.

You don't choose between them — the app picks whichever the host adapter implements for that combination of provider + form fields. GitHub.com gives you auth-code; smaller hosts may give you device flow.

Adding an OAuth credential

  1. Settings → Authentication → Add credential
  2. Pick your host
  3. Choose the OAuth method tab
  4. Fill in the fields the host needs (see Per-provider fields)
  5. Tap Sign in
  6. The in-app browser opens at your host's authorize URL
  7. Sign in (if you're not already), approve the scopes hachicode requests
  8. The browser closes and you're back in the app; the credential is saved

Per-provider fields

  • GitHub.com. No fields to fill in. The Client ID is baked into hachicode's GitHub OAuth app registration.
  • GitHub Enterprise. Requires Host (e.g. github.your-company.com) and Client ID. Your GHES admin registers hachicode as an OAuth app and gives you the Client ID; Client Secret may also be needed depending on app type.
  • GitLab.com / GitLab self-hosted. Requires Host and Client ID. For gitlab.com use gitlab.com. For self-hosted, register hachicode as an Application in admin settings.
  • Gitea. Requires Host and Client ID. Some Gitea versions support public clients (no secret); newer versions require the secret too.

What's stored after sign-in

When the flow completes the app stores:

  • The access token (encrypted at rest in the iOS Keychain)
  • The refresh token, if the host issued one
  • The token's expiry, if any
  • The granted scopes
  • Your username (looked up via the host's API right after sign-in)

Username discovery means you don't have to type it. Push / fetch use the access token directly; the token is sent only to the host it was issued for.

When tokens expire

Providers vary:

  • GitHub.com OAuth tokens don't expire by default unless you've granted limited-life tokens. If the token does expire the next push or fetch will fail with an auth error — re-sign-in from the credential editor (refresh icon ↻ in the list).
  • GitLab tokens typically include a refresh token. When the access token expires the app refreshes it automatically; you shouldn't see this.
  • Gitea depends on the instance configuration. Refresh-token behavior is the same as GitLab when supported.

If a refresh attempt fails, the app falls back to surfacing the auth error and you re-sign-in.

Re-signing in vs adding new

The refresh icon (↻) next to a credential runs the OAuth flow again for that credential. The result replaces the stored token; the credential id, host, and username stay the same. Projects pointing at this credential continue to work without changes.

Add credential creates a fresh credential, even if you sign in as the same user. Use this when you want a separate credential for a separate purpose, or when you signed in as a different user.

Common failures

  • "Host is malformed." The Host field expects a bare hostname (gitlab.example.com), not a URL — no https://, no trailing slash.
  • "Browser redirect did not include an OAuth callback." The browser session closed without returning the authorization code. Usually because you tapped Cancel or the host's authorize page errored. Re-try; if it persists check the host is reachable and the Client ID is correct.
  • "OAuth (auth code) not supported by this service." / "OAuth (device flow) not supported by this service." The selected adapter doesn't implement that flow shape. Pick the other OAuth method tab if available, or use a PAT.
  • Scope mismatch confirmation prompt: the host granted you a smaller set of scopes than the app asked for. Confirm to proceed with the reduced set, or cancel and re-do the consent screen.

See also

Last updated: