WebHooker/docs/api/oauth.md

91 lines
2.8 KiB
Markdown

# OAuth
WebHooker implements GitHub OAuth2 to enable user-initiated actions (comment, merge, react).
## Flow
```text
User → GET /auth/github → Redirect to GitHub → Authorize →
→ GET /auth/github/callback → Exchange code for token → Store in KV
```
## Endpoints
### Start OAuth
```
GET /auth/github
```
Redirects the user to GitHub's authorization page.
**Query Parameters:**
| Parameter | Description |
| ---------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `redirect` | Optional relative path to return to after sign-in (e.g. `/admin`). Must start with `/` but not `//`; any unsafe value falls back to `/`. |
**Response:** `302` redirect to GitHub OAuth authorize URL.
### OAuth Callback
```
GET /auth/github/callback
```
GitHub redirects here after authorization. Exchanges the code for an access token and stores it in KV.
**Query Parameters (from GitHub):**
| Parameter | Description |
| --------- | ----------------------------------- |
| `code` | Authorization code |
| `state` | State parameter for CSRF protection |
**Response:**
- **Browser flow** (`Accept: text/html`): sets an admin session cookie, then redirects to the `redirect` target. Users without admin access are redirected to `/admin?error=forbidden`.
- **JSON flow**: returns `{ "userId": "...", "login": "...", "redirectTo": "..." }`.
- **Discord link flow** (started with a pending `discordUserId`): links the Discord user to this GitHub account, returning `{ "ok": true, "discordUserId": "...", "login": "..." }` — or a success page in the browser.
### Revoke Token
```
DELETE /auth/token/:userId
```
Removes the stored OAuth token for a user.
**Response:**
```json
{
"ok": true
}
```
## Token Storage
Tokens are stored in KV with key pattern `token:{userId}`:
```json
{
"userId": "12345",
"accessToken": "gho_...",
"expiresAt": 1735689600000,
"refreshToken": "..."
}
```
`expiresAt` is a Unix timestamp in milliseconds. KV entries expire at 90% of the token's lifetime (minimum 60 seconds). A reverse index `token-reverse:{sha256 of token}` maps the access token back to its user id so Bearer-authenticated endpoints can resolve the caller. Discord users linked to a GitHub account are stored in the D1 `discord_links` table.
## Using Tokens
After OAuth, include the access token in the `Authorization` header for action API calls:
```bash
curl -X POST https://your-worker/api/comment \
-H "Authorization: Bearer gho_..." \
-H "Content-Type: application/json" \
-d '{"owner": "org", "repo": "repo", "issueNumber": 1, "body": "Hello!"}'
```