# Authentication

Every request to the review API carries a Proofline token in the `Authorization` header. A token works in one organization, with the scopes and repositories chosen when it was created.

```sh
curl -sS "https://proofline.sh/api/v1/organizations/$PROOFLINE_ORGANIZATION_ID/reviews" \
  -H "Authorization: Bearer $PROOFLINE_TOKEN"
```

```typescript
import { ProoflineClient } from "@proofline/sdk";

// The client sends the token in the Authorization header of every request.
const client = new ProoflineClient({
  baseUrl: "https://proofline.sh",
  token: process.env.PROOFLINE_TOKEN!,
});
const page = await client.listReviews({
  path: { org_id: process.env.PROOFLINE_ORGANIZATION_ID! },
});
console.log(page.items.length);
```

```python
import os
from uuid import UUID
from proofline import ProoflineClient

# The client sends the token in the Authorization header of every request.
with ProoflineClient(os.environ["PROOFLINE_TOKEN"]) as client:
    page = client.list_reviews(UUID(os.environ["PROOFLINE_ORGANIZATION_ID"]))
    print(len(page.items))
```

## Tokens

A token acts with its holder's current GitHub identity and access. It reads or requests reviews and never changes configuration, billing, seats, cloud access, integrations or other tokens. Those actions need a signed-in browser.

| Kind | Created by | Default lifetime | Longest lifetime |
| --- | --- | --- | --- |
| Personal | You, from **Personal tokens** in the account menu | 30 days | 90 days |
| Organization | An administrator, from the organization's **API tokens** settings | 90 days | 365 days |
| CLI device | A command-line tool, through [device sign-in](#device-sign-in) | 14 days | 14 days |

The console shows a token's secret once, when you create it. Revoking a token takes effect on its next request.

## Scopes

Each operation needs one scope. Give a token only the scopes its job needs.

| Scope | Operations |
| --- | --- |
| `analytics:read` | [`GET /exports/{dataset}`](/docs/api/#export-reviews) |
| `reviews:read` | [`listRepositories`](/docs/api/#list-repositories), [`listReviews`](/docs/api/#list-reviews), [`getReview`](/docs/api/#get-review), [`getReviewRouting`](/docs/api/#get-review-routing), [`getDeploymentReview`](/docs/api/#get-deployment-review), [`listPullRequestReviews`](/docs/api/#list-pull-request-reviews), [`getPullRequestReview`](/docs/api/#get-pull-request-review) |
| `findings:read` | [`getAssessment`](/docs/api/#get-assessment), [`getFinding`](/docs/api/#get-finding) |
| `guidance:read` | [`getReviewGuidance`](/docs/api/#get-review-guidance) |
| `reviews:rerun` | [`rerunReview`](/docs/api/#rerun-review) |
| `reviews:request` | [`requestPatchReview`](/docs/api/#request-patch-review), [`requestReview`](/docs/api/#request-review) |

A token can also be limited to a list of repositories. An organization token that requests or reruns reviews must name its repositories. A pull request review request and a rerun check that the holder can still write to the repository on GitHub. A review request for local changes checks that the holder can still read it, because that review is never posted to GitHub.

## Errors

Errors are RFC 9457 problem documents, and the HTTP status is authoritative.

| Status | Meaning |
| --- | --- |
| 400 | The request sent both a session cookie and a token. |
| 401 | The token is missing, malformed, expired or revoked. |
| 404 | The organization or object is outside what the token can see. |
| 429 | The token made more than 600 requests in a minute. Wait for `Retry-After`. |

A 404 also answers when the holder has left the organization, or when the administrator who created an organization token has lost that role.

## Device sign-in

A command-line tool signs in through your browser, so you never copy a token. The tool asks for a code, opens the approval page, and waits while you choose the organization, the scopes and the repositories.

1. The tool sends `POST /auth/device/code` with the scopes it wants. The response has a `device_code`, a `user_code`, a `verification_uri` and a `verification_uri_complete`.
2. The tool opens `verification_uri_complete` in your browser. The page shows the code, so you only check that it matches the one in your terminal.
3. You approve. The approval needs a signed-in browser session, and you can narrow the scopes and repositories first.
4. The tool polls `POST /auth/device/token` with the `device_code` and `grant_type=urn:ietf:params:oauth:grant-type:device_code`. It receives an `access_token`, a CLI device token that lasts 14 days, and an `organization_id` naming the organization you approved. The token works only there, so the tool puts that ID in every API path.

The code expires after 10 minutes. Poll every 5 seconds to start with. Before approval, polling returns `authorization_pending`; polling too fast returns `slow_down` and adds five seconds to the interval. An expired or used code returns `expired_token`. Each code issues one token, however many times it is polled.
