> ## Documentation Index
> Fetch the complete documentation index at: https://docs.shipfastai.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Authentication with JWT and OAuth providers

> Secure your app with JWT access and refresh tokens, OAuth login via Google and GitHub, email verification, and password reset flows.

Shipfastai includes a complete authentication system out of the box. You get JWT-based login with short-lived access tokens and long-lived refresh tokens, OAuth sign-in with Google and GitHub, email verification on registration, and a two-step password reset flow. All auth endpoints live under the `/api/auth` prefix.

<Warning>
  Access tokens expire after **30 minutes** by default. Your client must use the refresh token endpoint to obtain a new access token before the current one expires, or prompt the user to log in again.
</Warning>

## Registering a user

Send a `POST` request to `/api/auth/register` with the user's email, password, and full name. On success, the server creates the account, sends a verification email, and returns the new user object. The user is not yet verified at this point.

```json Request theme={null}
POST /api/auth/register
Content-Type: application/json

{
  "email": "ada@example.com",
  "password": "hunter2secret",
  "full_name": "Ada Lovelace"
}
```

```json Response — 200 OK theme={null}
{
  "id": "a1b2c3d4-0000-0000-0000-000000000001",
  "email": "ada@example.com",
  "full_name": "Ada Lovelace",
  "is_verified": false,
  "is_active": true,
  "created_at": "2026-04-09T10:00:00Z"
}
```

## Logging in

Send a `POST` request to `/api/auth/login` with the user's credentials. A successful response contains an `access_token`, a `refresh_token`, and the user object.

```json Request theme={null}
POST /api/auth/login
Content-Type: application/json

{
  "email": "ada@example.com",
  "password": "hunter2secret"
}
```

```json Response — 200 OK theme={null}
{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "user": {
    "id": "a1b2c3d4-0000-0000-0000-000000000001",
    "email": "ada@example.com",
    "full_name": "Ada Lovelace",
    "is_verified": false,
    "is_active": true
  }
}
```

Pass the `access_token` in the `Authorization: Bearer <token>` header on every subsequent request that requires authentication.

## Refreshing tokens

Access tokens are short-lived. When one expires, send the stored `refresh_token` to `/api/auth/refresh` to get a new pair of tokens without requiring the user to log in again.

```json Request theme={null}
POST /api/auth/refresh
Content-Type: application/json

{
  "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
```

```json Response — 200 OK theme={null}
{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
```

Refresh tokens are valid for **7 days**. After expiry, the user must log in again.

## OAuth login

To start an OAuth flow, direct the user's browser to `GET /api/auth/oauth/{provider}` where `{provider}` is either `google` or `github`. The endpoint returns an authorization URL and a state token.

```json Response — 200 OK theme={null}
{
  "authorization_url": "https://accounts.google.com/o/oauth2/auth?client_id=...",
  "state": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
```

Redirect the user to `authorization_url`. After the user grants access, the provider sends them back to `GET /api/auth/callback/{provider}?code=...&state=...`. The backend exchanges the code for the user's profile, creates or links the account, then issues tokens and redirects to:

```
{FRONTEND_URL}/auth/callback?access_token=<token>&refresh_token=<token>
```

OAuth users are automatically marked as verified. Accounts are matched by provider ID first, then by email address, so an existing email/password account is linked automatically if the OAuth email matches.

## Email verification

After registering, the user receives an email containing a verification link. That link includes a short-lived token (valid for **24 hours**). Submit that token to verify the account.

```json Request theme={null}
POST /api/auth/verify-email
Content-Type: application/json

{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
```

```json Response — 200 OK theme={null}
{
  "message": "Email verified successfully"
}
```

If the verification email expired or was lost, you can trigger a resend:

```json Request theme={null}
POST /api/auth/resend-verification
Content-Type: application/json

{
  "email": "ada@example.com"
}
```

The endpoint always returns `200` regardless of whether the email is registered, to prevent user enumeration.

## Password reset

Password reset is a two-step process.

**Step 1 — request a reset link**

```json Request theme={null}
POST /api/auth/forgot-password
Content-Type: application/json

{
  "email": "ada@example.com"
}
```

```json Response — 200 OK theme={null}
{
  "message": "If your email is registered, a password reset link has been sent"
}
```

The user receives an email with a reset link containing a token that is valid for **1 hour**.

**Step 2 — submit the new password**

```json Request theme={null}
POST /api/auth/reset-password
Content-Type: application/json

{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "new_password": "newstrongerpassword"
}
```

```json Response — 200 OK theme={null}
{
  "message": "Password reset successfully"
}
```

You can optionally validate the token before showing the form by calling `POST /api/auth/verify-reset-token` with `{ "token": "..." }`. It returns `{ "valid": true }` if the token is still usable.
