---
title: "Claim a reserved account via GitHub OAuth"
method: POST
path: "/v1/account/claim/social/github"
tags: ["claim"]
---

# Claim a reserved account via GitHub OAuth

`POST /v1/account/claim/social/github`

Claim ownership of a pre-registered (reserved) Grove account by proving control
of an attached GitHub identity via OAuth.

**Flow:**
1. The user obtains a GitHub OAuth access token client-side
2. The user submits the token here along with the Grove handle they want to claim
3. The server validates the token against GitHub's API
4. If the resolved GitHub identity matches an unverified
   GitHub identity attached to the reserved account, the account
   is transitioned to ``CLAIMED`` and a Grove session is issued.

**Enumeration defense:** all account-state failures (handle not found, organic
account, already-claimed account, OAuth identity doesn't match any unverified
identity on the account, malformed account) return the same generic 404. An
attacker who has a valid OAuth token cannot use this endpoint to enumerate
which Grove handles are reserved.

**Token errors** (invalid/expired OAuth token, platform API unavailable)
propagate as 400/502 from the underlying OAuth validator — these are
user-actionable and don't leak any account state.

The endpoint is rate-limited per client IP (independent from the claim lookup
limiter).

## Request body

- GitHubClaimRequest — Request model for ``POST /v1/account/claim/social/github``.
  - `handle` string, required — Grove handle of the reserved account being claimed (case-insensitive)
  - `access_token` string, required — Platform OAuth access token obtained client-side

## Response `200`

Successful Response

- LoginCompleteResponse — Response model for login complete.
  - `account_id` string, required — Account ID
  - `api_key` string, required — Grove API key (JWT)
  - `identity_type` string, required — Primary identity type
  - `identity_value` string, required — Primary identity value
  - `tipping_address` string, required — Server wallet address (for tipping)
  - `onchain_address` string, required

## Other responses

- `400` — Invalid or expired OAuth access token
- `404` — No claimable account matches the provided handle and OAuth identity
- `422` — Missing or malformed request body
- `429` — Rate limit exceeded for this client IP

---

[API](https://skmtc.net/grove/apis/grove-api.md) · [All operations](https://skmtc.net/grove/apis/grove-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/grove/grove-api/versions/f286b48a8105/schema)
