Authentication
Updated 2026-09-16
The API is per person: your application acts on behalf of someone who granted it permission. The mechanism is OAuth2 (authorization_code with PKCE), the same one the Ghosty mobile app uses.
Endpoints
Scopes
Request the ones you need separated by spaces. The server narrows them to your client's ceiling without failing: if you ask for files and your client doesn't have it, the token comes out without it. Scopes are frozen in the token; a new grant arrives only at the next login.
Flow
- Generate
code_verifier(43–128 characters) andcode_challenge = BASE64URL(SHA256(code_verifier)). OnlyS256is accepted. - Open in the browser:
- The person signs in (Google, Apple or email) and accepts. They return to your
redirect_uriwith?code=…&state=…. The code is valid for 60 seconds. - Exchange it:
- Use the token:
Refreshing
The access token lasts 1 hour; the refresh token, 90 days, and it rotates on every use: store the new one and discard the old. Reusing an already-rotated refresh token revokes the whole family (it is the signal of a theft).
Rule of thumb: 401 → refresh and retry once; 403 → a scope is missing, don't retry.
Confidential and public clients
- Public (mobile, SPA):
client_idonly; PKCE mandatory. - Confidential (backend): also
client_secret, viaclient_secret_postorAuthorization: Basic.
redirect_uri is compared exactly: no wildcards or sub-paths.
Errors
Getting a client_id
Client registration is manual while the API is in beta: write to with your app's name, the exact redirect_uris and the scopes you need. House clients (Teams, the mobile app) skip the consent screen; a third party always sees it.