> ## 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 endpoints: register, login, OAuth

> Full reference for all Shipfastai authentication endpoints including registration, login, token refresh, email verification, password reset, and OAuth.

The auth API handles the complete identity lifecycle: account creation, credential-based login, JWT token management, email verification, password recovery, and OAuth sign-in via Google or GitHub. All endpoints are mounted under the `/api/auth/` prefix.

***

## POST /api/auth/register

Create a new user account. After registration, a verification email is sent to the provided address.

<ParamField body="email" type="string" required>
  The user's email address. Must be a valid email format and not already registered.
</ParamField>

<ParamField body="password" type="string" required>
  The user's password in plain text. It is hashed before storage.
</ParamField>

<ParamField body="full_name" type="string">
  The user's display name. Optional.
</ParamField>

<CodeGroup>
  ```bash curl theme={null}
  curl --request POST \
    --url http://localhost:8000/api/auth/register \
    --header "Content-Type: application/json" \
    --data '{
      "email": "user@example.com",
      "password": "secure-password-123",
      "full_name": "Jane Smith"
    }'
  ```

  ```python Python theme={null}
  import requests

  response = requests.post(
      "http://localhost:8000/api/auth/register",
      json={
          "email": "user@example.com",
          "password": "secure-password-123",
          "full_name": "Jane Smith",
      },
  )
  print(response.json())
  ```
</CodeGroup>

**Response** — `UserResponse`:

<ResponseField name="id" type="string" required>
  UUID of the newly created user.
</ResponseField>

<ResponseField name="email" type="string" required>
  The registered email address.
</ResponseField>

<ResponseField name="full_name" type="string">
  The user's display name, if provided.
</ResponseField>

<ResponseField name="avatar_url" type="string">
  Profile picture URL. `null` for newly registered users.
</ResponseField>

<ResponseField name="is_active" type="boolean" required>
  Whether the account is active. `true` by default on registration.
</ResponseField>

<ResponseField name="is_verified" type="boolean" required>
  Whether the email has been verified. `false` until the verification link is clicked.
</ResponseField>

<ResponseField name="oauth_provider" type="string">
  The OAuth provider used to sign in (`google`, `github`), or `null` for password-based accounts.
</ResponseField>

<ResponseField name="subscription_status" type="string" required>
  Current subscription status (e.g., `free`, `active`, `cancelled`).
</ResponseField>

<ResponseField name="subscription_tier" type="string" required>
  Subscription tier (e.g., `free`, `pro`).
</ResponseField>

<ResponseField name="created_at" type="string" required>
  ISO 8601 timestamp of when the account was created.
</ResponseField>

```json theme={null}
{
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "email": "user@example.com",
  "full_name": "Jane Smith",
  "avatar_url": null,
  "is_active": true,
  "is_verified": false,
  "oauth_provider": null,
  "subscription_status": "free",
  "subscription_tier": "free",
  "created_at": "2024-01-15T10:30:00Z"
}
```

***

## POST /api/auth/login

Authenticate with email and password. Returns a JWT access token and refresh token.

<ParamField body="email" type="string" required>
  The user's registered email address.
</ParamField>

<ParamField body="password" type="string" required>
  The user's password.
</ParamField>

<CodeGroup>
  ```bash curl theme={null}
  curl --request POST \
    --url http://localhost:8000/api/auth/login \
    --header "Content-Type: application/json" \
    --data '{
      "email": "user@example.com",
      "password": "secure-password-123"
    }'
  ```

  ```python Python theme={null}
  import requests

  response = requests.post(
      "http://localhost:8000/api/auth/login",
      json={"email": "user@example.com", "password": "secure-password-123"},
  )
  data = response.json()
  ```
</CodeGroup>

**Response** — `Token`:

<ResponseField name="access_token" type="string" required>
  JWT access token. Valid for 30 minutes. Pass this in the `Authorization` header.
</ResponseField>

<ResponseField name="refresh_token" type="string" required>
  JWT refresh token. Use this to obtain a new access token after expiry.
</ResponseField>

<ResponseField name="token_type" type="string" required>
  Always `"bearer"`.
</ResponseField>

<ResponseField name="user" type="object">
  The authenticated user object. See `UserResponse` fields above.

  <Expandable title="user properties">
    <ResponseField name="id" type="string">UUID of the user.</ResponseField>
    <ResponseField name="email" type="string">User's email address.</ResponseField>
    <ResponseField name="full_name" type="string">User's display name.</ResponseField>
    <ResponseField name="is_verified" type="boolean">Email verification status.</ResponseField>
    <ResponseField name="subscription_status" type="string">Current subscription status.</ResponseField>
    <ResponseField name="subscription_tier" type="string">Current subscription tier.</ResponseField>
    <ResponseField name="created_at" type="string">Account creation timestamp.</ResponseField>
  </Expandable>
</ResponseField>

```json theme={null}
{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "bearer",
  "user": {
    "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "email": "user@example.com",
    "full_name": "Jane Smith",
    "is_verified": true,
    "subscription_status": "active",
    "subscription_tier": "pro",
    "created_at": "2024-01-15T10:30:00Z"
  }
}
```

***

## POST /api/auth/refresh

Exchange a valid refresh token for a new access token and refresh token pair. Both tokens are rotated on every call.

<ParamField body="refresh_token" type="string" required>
  A valid, unexpired refresh token previously issued by `/api/auth/login` or a prior `/api/auth/refresh` call.
</ParamField>

```bash theme={null}
curl --request POST \
  --url http://localhost:8000/api/auth/refresh \
  --header "Content-Type: application/json" \
  --data '{"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."}'
```

**Response** — `Token` (same shape as login, `user` field is `null`):

```json theme={null}
{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "bearer",
  "user": null
}
```

***

## POST /api/auth/logout

Log out the current user. Because JWTs are stateless, the server does not invalidate the token — the client is responsible for discarding both tokens from storage.

No request body required.

```bash theme={null}
curl --request POST \
  --url http://localhost:8000/api/auth/logout
```

**Response:**

```json theme={null}
{
  "message": "Successfully logged out"
}
```

***

## GET /api/auth/me

Return the profile of the currently authenticated user.

**Headers:**

<ParamField header="Authorization" type="string" required>
  `Bearer <access_token>`
</ParamField>

```bash theme={null}
curl --request GET \
  --url http://localhost:8000/api/auth/me \
  --header "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
```

**Response** — `UserResponse` (see fields above):

```json theme={null}
{
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "email": "user@example.com",
  "full_name": "Jane Smith",
  "avatar_url": null,
  "is_active": true,
  "is_verified": true,
  "oauth_provider": null,
  "subscription_status": "active",
  "subscription_tier": "pro",
  "created_at": "2024-01-15T10:30:00Z"
}
```

***

## POST /api/auth/verify-email

Verify a user's email address using the token sent to them after registration.

<ParamField body="token" type="string" required>
  The verification token extracted from the link in the verification email.
</ParamField>

```bash theme={null}
curl --request POST \
  --url http://localhost:8000/api/auth/verify-email \
  --header "Content-Type: application/json" \
  --data '{"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."}'
```

**Response:**

```json theme={null}
{
  "message": "Email verified successfully"
}
```

If the email was already verified, the response is:

```json theme={null}
{
  "message": "Email already verified"
}
```

***

## POST /api/auth/resend-verification

Resend the verification email to a registered address. This endpoint always returns `200` regardless of whether the email is registered, to prevent email enumeration.

<ParamField body="email" type="string" required>
  The email address to resend the verification link to.
</ParamField>

```bash theme={null}
curl --request POST \
  --url http://localhost:8000/api/auth/resend-verification \
  --header "Content-Type: application/json" \
  --data '{"email": "user@example.com"}'
```

**Response:**

```json theme={null}
{
  "message": "If your email is registered, a verification link has been sent"
}
```

***

## POST /api/auth/forgot-password

Request a password reset email. Like resend-verification, this always returns `200` to prevent email enumeration.

<ParamField body="email" type="string" required>
  The email address associated with the account.
</ParamField>

```bash theme={null}
curl --request POST \
  --url http://localhost:8000/api/auth/forgot-password \
  --header "Content-Type: application/json" \
  --data '{"email": "user@example.com"}'
```

**Response:**

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

***

## POST /api/auth/verify-reset-token

Check whether a password reset token is still valid before presenting the reset form to the user.

<ParamField body="token" type="string" required>
  The password reset token from the reset email link.
</ParamField>

```bash theme={null}
curl --request POST \
  --url http://localhost:8000/api/auth/verify-reset-token \
  --header "Content-Type: application/json" \
  --data '{"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."}'
```

**Response:**

```json theme={null}
{
  "valid": true
}
```

Returns `400` with `{"detail": "Invalid or expired reset token"}` if the token is invalid or expired.

***

## POST /api/auth/reset-password

Set a new password using a valid password reset token.

<ParamField body="token" type="string" required>
  The password reset token from the reset email link.
</ParamField>

<ParamField body="new_password" type="string" required>
  The new password to set for the account.
</ParamField>

```bash theme={null}
curl --request POST \
  --url http://localhost:8000/api/auth/reset-password \
  --header "Content-Type: application/json" \
  --data '{
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "new_password": "new-secure-password-456"
  }'
```

**Response:**

```json theme={null}
{
  "message": "Password reset successfully"
}
```

***

## GET /api/auth/oauth/{provider}

Initiate an OAuth sign-in flow. Returns the authorization URL that you redirect the user to. Supported providers are `google` and `github`.

<ParamField path="provider" type="string" required>
  The OAuth provider to use. Must be `google` or `github`. The provider must be configured in your backend settings.
</ParamField>

```bash theme={null}
curl --request GET \
  --url http://localhost:8000/api/auth/oauth/google
```

**Response:**

<ResponseField name="authorization_url" type="string" required>
  The full URL to redirect the user to in order to begin the OAuth flow.
</ResponseField>

<ResponseField name="state" type="string" required>
  A CSRF state token. Pass this back when handling the OAuth callback to validate the flow.
</ResponseField>

```json theme={null}
{
  "authorization_url": "https://accounts.google.com/o/oauth2/v2/auth?client_id=...&redirect_uri=...&state=...",
  "state": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
```

After the user authorizes the app, the provider redirects to `GET /api/auth/callback/{provider}`, which exchanges the code for tokens and redirects the browser to `{FRONTEND_URL}/auth/callback?access_token=...&refresh_token=...`.

<Note>
  The callback endpoint is handled automatically by the backend — you do not need to call it directly. Configure your OAuth app's redirect URI to point to `{your-backend-url}/api/auth/callback/{provider}`.
</Note>
