Docs
Search docs

List linked OAuth identities

GET/api/user/identities

listIdentities

Session-authenticated caller only. Lists the OAuth identities linked to the authenticated account.

Requires authentication using a session cookie — see tokens and scopes.

curl

curl -X GET 'https://neosource.dev/api/user/identities' \
  -b 'ns_session=$NEOSOURCE_SESSION'

fetch

fetch("https://neosource.dev/api/user/identities", {
  method: "GET",
  credentials: "include",
});

Responses

200Linked identity list

application/json

IdentityListResponse

object

identitiesrequired

array

items

IdentityResponse

object

identity_idrequired

string

last_used_at

integer | nullint64

linked_atrequired

integerint64

providerrequired

string

provider_email

string | null

provider_loginrequired

string

scopesrequired

array

Provider scopes recorded on this identity (e.g. `["read:user", "user:email", "repo"]`). Meaningful only for a classic OAuth App token (`token_kind: oauth_app`, or absent on a link that pre-dates the column); a GitHub App user-to-server token has none and reports an empty list. Empty when no scopes were recorded.

items

string

token_kind

403Forbidden — one of: forbidden, needs_scope

application/json

one of
  • ErrorForbidden
  • NeedsScopeError

    object

    `403` body returned when a classic OAuth token is asked for something its granted scopes do not cover — an explicit private listing without `repo`, or the one-click GitHub mirror without `admin:public_key`. `scope` names the missing grant so the client can say exactly what the token lacks. There is no elevation route to widen it any more (a re-link goes through the GitHub App, whose tokens carry no scopes), so the client's answer is to say so, never to start a handshake.

    errorrequired

    string

    Always `needs_scope` — this body exists to carry the extra fields that kind needs.

    "needs_scope"

    scoperequired

    string

    The provider scope to request via elevation (e.g. `"repo"`).

Standard errors

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

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

Schemas

Referenced above. Listed here rather than expanded inline, so the same definition is not repeated at every level.

ProviderTokenKind

string

Which kind of GitHub credential an identity's stored access token is — the fact every scope-shaped gate has to branch on now that production login runs on the GitHub **App**'s client id. A classic OAuth App token (`gho_…`) carries the scopes the user consented to, so `access_token_scopes` says what it can reach. A GitHub App user-to-server token (`ghu_…`) carries NO scopes at all — the token response's `scope` is empty and the `scope` query parameter is ignored — and reaches exactly the repositories where the App is installed and the user has access. A gate that reads scopes off such a token 403s forever, which is what this enum exists to make unrepresentable: every writer of an identity row states the kind, and every reader branches on it before it looks at a scope string. Stored as `account_identities.token_kind`; `NULL` there is a link made before the column existed, which is by construction a classic token.

"oauth_app""github_app_user"