# Auth

Sign-up and login for your app's own users with email and password, GitHub or Google, as a simple HTTP API.

## Deploy

Click Deploy on the Auth card. Auth works on its own with managed storage for users and sessions. If your project already has Postgres, Auth uses its `auth` schema by default. It gives you three values:

| Variable | Where to use it |
| --- | --- |
| `AUTH_URL` | The base address of your project's auth API. Safe in browser code. |
| `AUTH_PUBLISHABLE_KEY` | Identifies your project. Safe in browser code. Send it as the `x-api-key` header. |
| `AUTH_SECRET_KEY` | Unlocks admin endpoints. Server only. Never ship it to a browser or mobile app. |

Click Open Auth on the Auth card to search users, delete them, and change storage. The Store users in project database toggle moves users and sessions between managed storage and your running Postgres database; sign-in pauses briefly during the move. The free plan holds up to 10,000 registered users; Pro has no limit. The first 10,000 monthly active users per project are free on both plans; additional active users cost $0.003 each per month. Database and email usage remain subject to their own pricing and limits.

## How it works

- Every request sends the header `x-api-key: <AUTH_PUBLISHABLE_KEY>`.
- Sign-up and sign-in return `{ token, user }`. Keep the token and send it as `authorization: Bearer <token>` on later calls.
- No cookies are used, so the API works from any site, a mobile app or a server (CORS allows every origin).
- Passwords must be at least 8 characters.

## Endpoints

| Method and path | Body or header | Returns |
| --- | --- | --- |
| `POST {AUTH_URL}/sign-up/email` | `{ name, email, password }` | `{ token, user }` |
| `POST {AUTH_URL}/sign-in/email` | `{ email, password }` | `{ token, user }` |
| `GET {AUTH_URL}/get-session` | `authorization: Bearer <token>` | The session and user, or null when signed out |
| `POST {AUTH_URL}/sign-out` | `authorization: Bearer <token>` | Ends the session |
| `GET {AUTH_URL}/admin/users?search=&limit=50&offset=0` | `x-api-key: <AUTH_SECRET_KEY>` | `{ users, total }` |
| `DELETE {AUTH_URL}/admin/users/<id>` | `x-api-key: <AUTH_SECRET_KEY>` | `{ deleted: true }` |

Errors come back as `{ message }` with a status code: 401 for a missing or wrong key, 403 when an admin endpoint is called with the publishable key, 503 while storage is moving, or when Auth uses a project database that is asleep or not running.

## GitHub and Google sign-in

On the Auth card, open Sign in with GitHub or Google and choose a credential source for each provider. Shared uses CloudHike.dev's OAuth app. Your own uses the client ID and client secret of an OAuth app you registered, with the callback URL `<AUTH_URL>/callback/github` (or `/google`) shown on the card.

Add each site your app runs on, one per line, under Sites users can return to. Users are sent back only to those sites.

*Sign in with GitHub*

```ts
// Send the browser to the provider. It returns to `to` with the token in the fragment.
const to = location.origin + "/";
window.location.href = `${AUTH_URL}/social/github?to=${encodeURIComponent(to)}`;

// On your page after sign-in: take the token from the fragment, then clear it.
const params = new URLSearchParams(location.hash.slice(1));
const token = params.get("token");          // send it as authorization: Bearer <token>
const error = params.get("error");          // set when sign-in was not completed
history.replaceState(null, "", location.pathname);
```

- Browsers only: the start link is a page navigation, so it cannot send the x-api-key header. Calling `POST {AUTH_URL}/sign-in/social` from code is refused.
- The fragment is never sent to a server, so the token stays out of logs. Store it as you would the email sign-in token.
- Users who sign in with a provider appear in the same Users list, with the email their provider gives. GitHub's is a verified primary address.

## Email and password

Email and password sign-up is always on. Two options on the Auth page's Providers tab control the emails: Require a verified email before sign-in, and the sites users may return to. Emails come from CloudHike.dev's sender, so you do not configure SMTP.

- With verification on, sign-up sends a link. Sign-in returns 403 until the user opens it; the link then returns them to your site.
- Forgotten password: `POST {AUTH_URL}/request-password-reset` with `{ email, redirectTo }`. The user gets a link that returns them to `redirectTo` with a `token` in the query.
- Set the new password with `POST {AUTH_URL}/reset-password` with `{ newPassword, token }` and your publishable key.
- Resend a verification email with `POST {AUTH_URL}/send-verification-email` with `{ email, callbackURL }`.

## Examples

*lib/auth.ts*

```ts
const AUTH_URL = process.env.AUTH_URL!;
const headers = {
  "content-type": "application/json",
  "x-api-key": process.env.AUTH_PUBLISHABLE_KEY!,
};

export async function signUp(name: string, email: string, password: string) {
  const res = await fetch(`${AUTH_URL}/sign-up/email`, {
    method: "POST",
    headers,
    body: JSON.stringify({ name, email, password }),
  });
  if (!res.ok) throw new Error((await res.json()).message);
  return res.json() as Promise<{ token: string; user: { id: string; email: string } }>;
}

export async function signIn(email: string, password: string) {
  const res = await fetch(`${AUTH_URL}/sign-in/email`, {
    method: "POST",
    headers,
    body: JSON.stringify({ email, password }),
  });
  if (!res.ok) throw new Error((await res.json()).message);
  return res.json();
}

export async function getSession(token: string) {
  const res = await fetch(`${AUTH_URL}/get-session`, {
    headers: { ...headers, authorization: `Bearer ${token}` },
  });
  return res.ok ? res.json() : null;
}
```

*curl*

```bash
curl -X POST "$AUTH_URL/sign-up/email" \
  -H "x-api-key: $AUTH_PUBLISHABLE_KEY" \
  -H "content-type: application/json" \
  -d '{"name":"Ada","email":"ada@example.com","password":"correct-horse-battery"}'
```

Store the token in an HTTP-only cookie that your own server sets, then call `get-session` from server code on each request. This keeps the token away from page scripts.

## Good to know

- Click Reset keys on the Auth card if the secret key leaks. Users stay signed in, because sessions are signed with a separate per-project secret.
- Auth is billed per active user: each end user who signed in during the month costs a small amount (see Plans, limits and billing).
- When Auth uses your project database, that database must stay running. Auth with managed storage works independently of your project database.

## Use with AI

Ask an agent to add sign-up, login and protected pages to your app using your project's Auth API.

```text
Read https://cloudhike.dev/docs/md/auth, then add user authentication to this app using my CloudHike.dev Auth service.

- AUTH_URL, AUTH_PUBLISHABLE_KEY and AUTH_SECRET_KEY are in my env file (if not, follow https://cloudhike.dev/prompt.md to download them).
- Build sign-up, sign-in, sign-out and a way to read the current user.
- Keep the returned token in an HTTP-only cookie set by the server, and send it as an Authorization Bearer header.
- Use AUTH_SECRET_KEY only in server code, never in the browser.
- Match this app's existing framework, styling and form patterns.
```
