neosourceDocs
Search docs

Begin an OAuth handshake (login or handle claim)

POST/api/auth/oauth/{provider}/start

startOauth

Creates a state row and returns the provider's authorize URL. Intent is one of `login` or `claim_handle`. Use the separate `/link` endpoint for `link`.

Authentication is not described for this operation in the spec — that does not mean it is public. Check tokens and scopes.

curl

curl -X POST 'https://neosource.dev/api/auth/oauth/PROVIDER/start' \
  -H 'Content-Type: application/json' \
  -d '{"intent":"string"}'

fetch

fetch("https://neosource.dev/api/auth/oauth/PROVIDER/start", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
  },
  body: JSON.stringify({"intent":"string"}),
});

Path parameters

providerrequired

One of: `github`. Extend as more providers come online.

string

Request bodyrequired

application/json

OAuthStartRequest

object

claim_handle

string | null

`neosource` handle the user is trying to claim; required when `intent = "claim_handle"`. The callback enforces the provider login matches this value (case-insensitive).

intentrequired

OAuthIntent

string

"login""link""claim_handle"

requested_scope
one of
  • null

  • OAuthScope

    string

    How much provider access an OAuth handshake should request. Drives incremental authorization (see `plans/github-onboarding-tiers.md`): login asks for the minimum, and elevated tiers are requested only when the user opts into the feature that needs them. The provider client maps each tier onto the concrete provider scope string.

    "minimal""repo""repo_and_deploy_key"

return_to

string | null

Internal path the SPA wants to land on after the callback. Only values starting with `/` (and not `//`) are honoured.

additional propertiesnot allowed

Responses

200Redirect URL

application/json

OAuthStartResponse

object

redirect_urlrequired

string

Standard errors

Bodies documented once for the whole API — see standard errors.

  • 400Bad Request — one of: invalid_input
  • 403Forbidden — one of: forbidden
  • 429Rate limited — retry after the `Retry-After` header
  • 500Internal server error
  • 502Bad Gateway — one of: upstream
  • 503Service temporarily unavailable / at capacity — retry after the `Retry-After` header
  • 504Gateway timeout — the request exceeded the server's handling budget