> ## Documentation Index
> Fetch the complete documentation index at: https://personal-ce79cb71.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# BugViper API Authentication — GitHub OAuth and Tokens

> Learn how to obtain a Firebase ID Token via GitHub OAuth and include it as a Bearer token on every protected BugViper API request.

BugViper uses Firebase Authentication backed by GitHub OAuth. Every protected API request must include a valid **Firebase ID Token** in the `Authorization` header. This page explains how the auth flow works, how to obtain a token, and documents every endpoint in the `/api/v1/auth/` group.

## How Authentication Works

1. **Sign in with GitHub** — The user visits the BugViper `/login` page (or a GitHub OAuth popup in the dashboard). They authorize the BugViper OAuth app, and GitHub returns a short-lived access token.
2. **Call `/api/v1/auth/login`** — BugViper's frontend sends that GitHub access token to `POST /api/v1/auth/login`. The API fetches the user's GitHub profile and creates or updates their BugViper user record.
3. **Firebase issues an ID Token** — Firebase generates a signed JWT (the **ID Token**) tied to the authenticated user. This token is valid for **1 hour** and can be silently refreshed by the Firebase SDK.
4. **Pass the token on every request** — Include the token as a Bearer credential in the `Authorization` header for every protected endpoint.

```
Authorization: Bearer <Firebase ID Token>
```

### Passing the Token

Here is an example using curl:

```bash theme={null}
curl -X GET https://your-domain.com/api/v1/auth/me \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiJ9..."
```

<Tip>
  You can copy a live token from the browser's developer console while signed in to the BugViper dashboard: call `await firebase.auth().currentUser.getIdToken()` in the console to print the current JWT.
</Tip>

### Token Expiry and Refresh

Firebase ID Tokens expire after **1 hour**. The BugViper frontend refreshes them automatically using the Firebase SDK's token refresh mechanism. For server-side or scripted integrations, call `getIdToken(/* forceRefresh= */ true)` on the Firebase user object before each batch of requests to ensure the token is still valid.

<Warning>
  Passing an expired token returns `HTTP 401 Unauthorized`. Always refresh the token before it expires in long-running scripts or background jobs.
</Warning>

***

## Auth Endpoint Reference

### POST /api/v1/auth/login

Register a new user or sign in an existing one. Pass the GitHub OAuth access token obtained from GitHub's OAuth flow. The API fetches the user's GitHub profile and creates or updates the corresponding BugViper user record. Returns the full user profile.

```bash theme={null}
curl -X POST https://your-domain.com/api/v1/auth/login \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiJ9..." \
  -H "Content-Type: application/json" \
  -d '{"github_access_token": "gho_xxxxxxxxxxxx"}'
```

**Request body**

<ParamField body="github_access_token" type="string" required>
  The GitHub OAuth access token obtained after the user completes the GitHub OAuth flow. Starts with `gho_` for classic tokens.
</ParamField>

**Example request body**

```json theme={null}
{
  "github_access_token": "gho_xxxxxxxxxxxx"
}
```

**Example response**

```json theme={null}
{
  "uid": "firebase-uid-abc123",
  "email": "alice@example.com",
  "displayName": "Alice Smith",
  "githubUsername": "alicesmith",
  "photoURL": "https://avatars.githubusercontent.com/u/12345678",
  "createdAt": "2024-09-01T10:00:00Z",
  "githubInstallationId": 987654,
  "accountType": "User",
  "repositorySelection": "selected"
}
```

***

### POST /api/v1/auth/ensure

Ensures the authenticated user's record exists. Call this on returning sessions when you already hold a valid Firebase ID Token but do not have a fresh GitHub access token — for example, when the page reloads and Firebase silently re-authenticates.

No request body is required. The API identifies the user from the `Authorization` header alone.

```bash theme={null}
curl -X POST https://your-domain.com/api/v1/auth/ensure \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiJ9..."
```

**Response:** user profile object (same shape as `/auth/login`).

<Note>
  Use `/api/v1/auth/ensure` instead of `/api/v1/auth/login` for session restores. It is faster because it only verifies the existing user record without making an additional GitHub API call.
</Note>

***

### GET /api/v1/auth/me

Returns the authenticated user's profile. Use this to verify the current token is valid and to retrieve profile data without going through the login flow again.

```bash theme={null}
curl -X GET https://your-domain.com/api/v1/auth/me \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiJ9..."
```

**Response fields**

<ResponseField name="uid" type="string">
  Firebase user ID. Uniquely identifies the user across all BugViper services.
</ResponseField>

<ResponseField name="email" type="string">
  The user's email address as provided by GitHub.
</ResponseField>

<ResponseField name="displayName" type="string">
  The user's display name from their GitHub profile.
</ResponseField>

<ResponseField name="githubUsername" type="string">
  The user's GitHub username (e.g., `alicesmith`).
</ResponseField>

<ResponseField name="photoURL" type="string">
  URL to the user's GitHub avatar image.
</ResponseField>

<ResponseField name="createdAt" type="string">
  ISO 8601 timestamp of when the user account was first created in BugViper.
</ResponseField>

<ResponseField name="githubInstallationId" type="number | null">
  The GitHub App installation ID linked to this user's account. `null` if the GitHub App has not been installed yet.
</ResponseField>

<ResponseField name="accountType" type="string">
  GitHub account type — `"User"` or `"Organization"`.
</ResponseField>

<ResponseField name="repositorySelection" type="string">
  The repository selection scope chosen when installing the GitHub App — `"all"` or `"selected"`.
</ResponseField>

**Example response**

```json theme={null}
{
  "uid": "firebase-uid-abc123",
  "email": "alice@example.com",
  "displayName": "Alice Smith",
  "githubUsername": "alicesmith",
  "photoURL": "https://avatars.githubusercontent.com/u/12345678",
  "createdAt": "2024-09-01T10:00:00Z",
  "githubInstallationId": 987654,
  "accountType": "User",
  "repositorySelection": "selected"
}
```

***

### GET /api/v1/auth/github/repos

Returns the list of GitHub repositories accessible to the authenticated user. This is the same repository list you see when connecting repos in the BugViper dashboard.

```bash theme={null}
curl -X GET https://your-domain.com/api/v1/auth/github/repos \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiJ9..."
```

<Warning>
  This endpoint returns `HTTP 400` if no GitHub access token is stored for the user. Make sure you have called `POST /api/v1/auth/login` at least once with a valid GitHub token before calling this endpoint.
</Warning>

**Response:** array of repository objects.

<ResponseField name="name" type="string">
  Short repository name (e.g., `my-project`).
</ResponseField>

<ResponseField name="full_name" type="string">
  Full repository name including the owner (e.g., `alicesmith/my-project`).
</ResponseField>

<ResponseField name="description" type="string | null">
  Repository description as set on GitHub.
</ResponseField>

<ResponseField name="language" type="string | null">
  Primary programming language detected by GitHub.
</ResponseField>

<ResponseField name="stargazers_count" type="number">
  Number of GitHub stars.
</ResponseField>

<ResponseField name="private" type="boolean">
  Whether the repository is private.
</ResponseField>

<ResponseField name="default_branch" type="string">
  Name of the repository's default branch (e.g., `main` or `master`).
</ResponseField>

<ResponseField name="html_url" type="string">
  URL to the repository's GitHub page.
</ResponseField>

**Example response**

```json theme={null}
[
  {
    "name": "my-project",
    "full_name": "alicesmith/my-project",
    "description": "A sample project",
    "language": "TypeScript",
    "stargazers_count": 42,
    "private": false,
    "default_branch": "main",
    "html_url": "https://github.com/alicesmith/my-project"
  }
]
```

***

### GET /api/v1/auth/installation

Returns the GitHub App installation status for the currently authenticated user. Use this to determine whether the user has installed the BugViper GitHub App and linked it to their account — a prerequisite for receiving PR review webhooks.

```bash theme={null}
curl -X GET https://your-domain.com/api/v1/auth/installation \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiJ9..."
```

**Response fields**

<ResponseField name="linked" type="boolean">
  `true` if the BugViper GitHub App is installed and successfully linked to this user's account. `false` if the app has not been installed or the installation could not be resolved.
</ResponseField>

<ResponseField name="installationId" type="number | null">
  The GitHub App installation ID. Present when `linked` is `true`; `null` otherwise.
</ResponseField>

<ResponseField name="githubUsername" type="string | null">
  The GitHub username associated with this account.
</ResponseField>

<ResponseField name="settingsUrl" type="string | null">
  A direct link to the GitHub App installation settings page (`https://github.com/settings/installations/{installationId}`). Present when `linked` is `true`; `null` otherwise.
</ResponseField>

**Example response — linked**

```json theme={null}
{
  "linked": true,
  "installationId": 987654,
  "githubUsername": "alicesmith",
  "settingsUrl": "https://github.com/settings/installations/987654"
}
```

**Example response — not linked**

```json theme={null}
{
  "linked": false,
  "installationId": null,
  "githubUsername": "alicesmith",
  "settingsUrl": null
}
```

<Note>
  If `linked` is `false`, direct the user to install the BugViper GitHub App from the dashboard's **Settings** page. Once installed, the next call to `/api/v1/auth/installation` will automatically attempt to link the pending installation to the user's account.
</Note>
