> ## Documentation Index
> Fetch the complete documentation index at: https://doc.playsmart.api.dolly.gg/llms.txt
> Use this file to discover all available pages before exploring further.

# POST /auth/login — Log in and receive JWT tokens

> Log in an existing PlaySmart player with email and password. Returns fresh JWT access and refresh tokens with the player's current profile.

Calling this endpoint authenticates an existing player and returns a fresh pair of JWT tokens. The response shape is identical to `POST /auth/register`, so your token-handling code works for both flows without modification.

## Endpoint

```text theme={null}
POST /auth/login
```

No authentication is required.

## Request body

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

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

## Example request

```bash theme={null}
curl -X POST https://playsmart-gateway-1w8ko864.uc.gateway.dev/auth/login \
  -H "Content-Type: application/json" \
  -d '{
    "email": "player@example.com",
    "password": "s3cur3pass"
  }'
```

## Response

### 200 OK

<ResponseField name="access_token" type="string">
  A signed JWT bearer token. Include this in the `Authorization: Bearer` header on every authenticated request. Expires in 30 days.
</ResponseField>

<ResponseField name="refresh_token" type="string">
  A signed JWT refresh token. Use this to obtain a new access token when the current one expires. Expires in 180 days.
</ResponseField>

<ResponseField name="user" type="object">
  <Expandable title="properties">
    <ResponseField name="id" type="string">
      The player's unique identifier. Matches the `auth_user_id` stored on the account and the `sub` claim in the JWT.
    </ResponseField>

    <ResponseField name="email" type="string">
      The player's email address.
    </ResponseField>

    <ResponseField name="pseudo" type="string">
      The player's display name.
    </ResponseField>

    <ResponseField name="total_games_completed" type="number">
      Total games the player has completed.
    </ResponseField>
  </Expandable>
</ResponseField>

```json theme={null}
{
  "data": {
    "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "user": {
      "id": "device-abc-123",
      "email": "player@example.com",
      "pseudo": "CoolPlayer99",
      "total_games_completed": 42
    }
  }
}
```

## Error responses

| HTTP status        | Code           | Message               | Meaning                                                                     |
| ------------------ | -------------- | --------------------- | --------------------------------------------------------------------------- |
| `400 BAD_REQUEST`  | `BAD_REQUEST`  | `invalid_payload`     | The request body failed validation. Check `details` for field-level errors. |
| `401 UNAUTHORIZED` | `UNAUTHORIZED` | `invalid_credentials` | No account exists for this email, or the password is incorrect.             |

```json theme={null}
{
  "error": {
    "code": "UNAUTHORIZED",
    "message": "invalid_credentials"
  }
}
```
