# AISafe auth.md

You are an agent. AISafe supports **agentic registration**: you can create an
AISafe account for your user, get a credential for the AISafe REST API, and
call the API with it. Follow the steps in order.

- Resource server: `https://api.aisafe.io` (REST API under `/api/v1`)
- Account and sign-in pages: `https://app.aisafe.io`
- OpenAPI description: https://docs.aisafe.io/openapi/v1.json
- API catalog: https://aisafe.io/.well-known/api-catalog

This page is for agents and scripts that act for a person or a company:
creating an AISafe account, listing assessments, reading findings,
downloading reports, or starting a new assessment.

Every account belongs to a real email address or a real GitHub or Google
identity, so register only with an identity your user controls and has agreed
to use for AISafe. Registration has no CAPTCHA; rate limits protect it
instead.

## Step 1: Pick a method

| Method | Needs | Works without a browser |
|---|---|---|
| Verified email | An email inbox you or your user can read | Yes |
| GitHub | A GitHub account with a verified email, signed in in a browser | No |
| Google | A Google account with a verified email, signed in in a browser | No |

If the email address or provider identity already has an AISafe account,
registration does not create a second one. Sign in instead (Step 5).

AISafe issues two credential types:

- `access_token`: a session token returned by email registration and login.
  It works on every plan, including Free, acts with the account's full role,
  and expires after `expires_in` seconds (48 hours).
- `api_key`: a key that starts with `sk-ais-`. It belongs to one organization,
  acts as the person who created it, and carries only the scopes chosen when
  it was created. Only the Pro and Enterprise plans can create API keys.

## Step 2: Register with a verified email

### 2a. Start the signup

```http
POST /api/v1/auth/signup HTTP/1.1
Host: api.aisafe.io
Content-Type: application/json

{"email": "agent-owner@example.com"}
```

The response is always the same, whether or not the address already has an
account, so it does not reveal who is registered:

```json
{"requires_confirmation": true, "message": "..."}
```

To join an existing organization, add the `invite_code` from its invitation:
`{"email": "...", "invite_code": "..."}`.

### 2b. Read the confirmation email

AISafe emails a link of the form
`https://app.aisafe.io/confirm-email?token=<token>` to the address. The token
is valid for 24 hours and can be used once. If the email does not arrive,
request a new one (at most 3 per hour):

```http
POST /api/v1/auth/resend-confirmation HTTP/1.1
Host: api.aisafe.io
Content-Type: application/json

{"email": "agent-owner@example.com"}
```

### 2c. Finish the account

Either open the link in a browser and fill in the form, or send the token
yourself. The password must be at least 12 characters long.

```http
POST /api/v1/auth/confirm-email HTTP/1.1
Host: api.aisafe.io
Content-Type: application/json

{
  "token": "<token from the link>",
  "password": "<a new password of 12 or more characters>",
  "first_name": "Ada",
  "last_name": "Lovelace"
}
```

The account is now active, with its own organization (or the invited one),
and the response signs it in:

```json
{"access_token": "<session token>", "token_type": "bearer", "expires_in": 172800}
```

Store the password as a secret. You need it to get a new `access_token`.

## Step 3: Register with GitHub or Google (browser only)

GitHub and Google registration only works in a browser, because the provider
asks the person to approve AISafe and AISafe binds the result to that browser.

1. In a browser, open https://app.aisafe.io/signup and choose GitHub or
   Google. The same flows start at
   `GET https://api.aisafe.io/api/v1/auth/github/signup` and
   `GET https://api.aisafe.io/api/v1/auth/google/signup`, which both accept
   an optional `invite_code` query parameter.
2. Approve AISafe at the provider. AISafe only accepts an email address that
   the provider has verified.
3. The browser lands on https://app.aisafe.io, signed in, with a new
   organization.

The session stays in the browser. To call the REST API from outside the
browser afterwards, either create an `api_key` (Step 4) or set a password
under https://app.aisafe.io/settings and sign in with it (Step 5).

## Step 4: Use the credential

Send either credential type as a bearer token on every request:

```http
GET /api/v1/assessments HTTP/1.1
Host: api.aisafe.io
Authorization: Bearer <access_token or api_key>
```

Prefer an `api_key` for a long-running agent on a Pro or Enterprise plan. It
does not expire unless its creator or the organization's policy sets an
expiry, and two-factor authentication does not affect it. Create one in the
app at https://app.aisafe.io/api-keys, or with an `access_token` that belongs
to an organization owner or admin:

```http
POST /api/v1/auth/api-keys HTTP/1.1
Host: api.aisafe.io
Authorization: Bearer <access_token>
Content-Type: application/json

{"name": "my-agent", "scopes": ["assessments:read", "findings:read"]}
```

The response contains the full key in `key`. It is shown only once, so store
it as a secret right away. Choose only the scopes the agent needs; a key can
never hold more access than the person who creates it, and wildcard scopes
are reserved for organization owners. The scope names are listed in the
OpenAPI description.

## Step 5: Sign in again

An `access_token` has no `refresh_token`. When it expires, get a new one with
the email and password:

```http
POST /api/v1/auth/login HTTP/1.1
Host: api.aisafe.io
Content-Type: application/json

{"email": "agent-owner@example.com", "password": "<password>"}
```

The response is the same `access_token` object as in Step 2c. If the account
has two-factor authentication turned on, the response is instead
`{"requires_2fa": true, "partial_token": "..."}`; send that token with a
current code to `POST /api/v1/auth/login/2fa` within 5 minutes.

## Errors

| Status | Meaning | What to do |
|---|---|---|
| `400` | The confirmation token is invalid, expired or used, or a field is wrong | Read `detail`; request a new confirmation email if the token expired |
| `401` | The credential is missing, expired, revoked or wrong | Sign in again, or ask the user for a new `api_key` |
| `403` | The key lacks the scope, or the plan does not include API keys | Do not retry; tell the user which call failed |
| `404` on signup | Registration is turned off on this instance | Ask an existing member for an invitation |
| `422` | The request body does not match the schema | Fix the body using the OpenAPI description |
| `429` | A rate limit was hit | Wait and retry later; honor `Retry-After` when present |

Signup allows 1000 requests per hour per IP address, confirming an email 10
per hour, and password login 10 attempts per 15 minutes per address and per
email. Do not retry a refused request in a loop.

## Revocation

Organization owners and admins can revoke any `api_key` in their organization
at https://app.aisafe.io/api-keys, and a key stops working when its creator
leaves the organization. `POST /api/v1/auth/logout` with an `access_token`
ends that session. Treat a `401` on a credential that used to work as
revocation: drop it and register or sign in again.

## Sign in with AISafe (for apps, not agents)

AISafe is also an OpenID Connect provider for approved web apps that let
people sign in with their AISafe account. Its discovery document is
https://api.aisafe.io/.well-known/openid-configuration. Tokens issued this
way identify a person to that app; they do not grant access to the REST API.
