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

# Authentication & Authorization

> Authenticate with the MediSync API using JWT tokens

## Overview

The MediSync API uses **JWT (JSON Web Token)** authentication to secure all protected endpoints. The same token authenticates the Dashboard (REST) API and the Speech (WebSocket) API. This guide covers registration, login, and how to use and manage tokens.

## Authentication flow

<Steps>
  <Step title="Register">
    Create a MediSync account with your professional credentials.
  </Step>

  <Step title="Log in">
    Authenticate with email and password to receive a JWT token.
  </Step>

  <Step title="Use the token">
    Send the JWT as a Bearer token in the `Authorization` header on every protected request.
  </Step>
</Steps>

<Note>
  There is **no refresh-token endpoint**. When a token expires, call `POST /api/login` again to obtain a new one.
</Note>

## Registration

Register a new healthcare-professional account:

```bash theme={null}
curl -X POST https://app.medisync.me/api/register \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Dr.",
    "firstName": "John",
    "lastName": "Doe",
    "email": "doctor@example.com",
    "password": "your_password",
    "specialty": "Cardiology",
    "ehr_system_type": "Epic",
    "ehr_system_name": "Epic MyChart"
  }'
```

**Response (`201 Created`):**

```json theme={null}
{
  "success": true,
  "result": {
    "_id": "6578a1b2c3d4e5f601234567",
    "title": "Dr.",
    "firstName": "John",
    "lastName": "Doe",
    "email": "doctor@example.com",
    "specialty": "Cardiology",
    "ehr_system_type": "Epic",
    "ehr_system_name": "Epic MyChart",
    "isVerified": false
  }
}
```

<Warning>
  New accounts are created **unverified** and a verification email is sent. Email verification is enforced at **login** — an unverified account cannot log in (see the error responses below).
</Warning>

<AccordionGroup>
  <Accordion icon="user-doctor" title="Fields">
    * **firstName** (required)
    * **lastName** (required)
    * **email** (required, must be unique)
    * **password** (required, minimum 6 characters)
    * **specialty** (required)
    * **ehr\_system\_type** (required) — EHR system category
    * **ehr\_system\_name** (required) — specific EHR system name
    * **title** (optional) — medical title (Dr., Prof.)
  </Accordion>

  <Accordion icon="shield-check" title="Password requirements">
    Minimum **6 characters**. No additional complexity rules are enforced, but a strong, unique password is strongly recommended.
  </Accordion>
</AccordionGroup>

**Registration errors:**

<CodeGroup>
  ```json 409 Email already registered theme={null}
  {
    "error": "Diese E-Mail-Adresse ist bereits registriert."
  }
  ```

  ```json 400 Validation failed theme={null}
  {
    "error": "Bitte geben Sie ein Passwort mit mindestens 6 Zeichen ein."
  }
  ```
</CodeGroup>

## Login

Authenticate with your credentials to obtain a JWT token:

```bash theme={null}
curl -X POST https://app.medisync.me/api/login \
  -H "Content-Type: application/json" \
  -d '{
    "email": "doctor@example.com",
    "password": "your_password",
    "remember": false
  }'
```

**Success response (`200 OK`):**

```json theme={null}
{
  "success": true,
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "uid": "6578a1b2c3d4e5f601234567",
  "userTitle": "Dr.",
  "firstName": "John",
  "lastName": "Doe",
  "twoFactorEnabled": false
}
```

### Login parameters

| Parameter       | Type    | Required | Description                                               |
| --------------- | ------- | -------- | --------------------------------------------------------- |
| `email`         | string  | Yes      | Registered email address                                  |
| `password`      | string  | Yes      | Account password (min 6 characters)                       |
| `remember`      | boolean | No       | Issue a 7-day token instead of 24 hours (default `false`) |
| `twoFactorCode` | string  | No       | TOTP or backup code, for accounts with 2FA enabled        |

### Two-factor authentication

If an account has 2FA enabled and `twoFactorCode` is omitted, login returns **`202 Accepted`** with a challenge — resubmit with the `twoFactorCode` included.

```json theme={null}
{
  "success": true,
  "requires2FA": true,
  "message": "Bitte geben Sie Ihren 2FA-Code ein."
}
```

### Login errors

Platform messages are returned in **German**, and authentication failures use a `failed` label alongside `error`.

<CodeGroup>
  ```json 401 Invalid email or password theme={null}
  {
    "failed": "Unauthorized Access",
    "error": "Ungültige E-Mail oder Passwort."
  }
  ```

  ```json 401 Email not verified theme={null}
  {
    "failed": "Email Not Verified",
    "error": "Bitte bestätigen Sie Ihre E-Mail-Adresse, bevor Sie sich anmelden.",
    "needsVerification": true
  }
  ```

  ```json 429 Too many attempts theme={null}
  {
    "error": "Zu viele Anmeldeversuche. Bitte versuchen Sie es in 15 Minuten erneut.",
    "rateLimited": true
  }
  ```
</CodeGroup>

## Using JWT tokens

Include your token in the `Authorization` header for all protected endpoints:

```bash theme={null}
Authorization: Bearer YOUR_JWT_TOKEN
```

### Example request

```bash theme={null}
curl -X GET https://app.medisync.me/api/user/profile \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
```

### Token structure

MediSync tokens are HS256-signed JWTs that carry your user identity and standard `iat`/`exp` claims:

```json theme={null}
{
  "header": { "alg": "HS256", "typ": "JWT" },
  "payload": {
    "_id": "6578a1b2c3d4e5f601234567",
    "email": "doctor@example.com",
    "iat": 1751440000,
    "exp": 1751526400
  }
}
```

<Note>
  Treat the token as **opaque**. It may include additional internal claims; do not depend on its internal structure. The server extracts your user id from the token, so no separate `uid` parameter is ever required.
</Note>

## Authorization

### User identification

User identification is handled entirely through the JWT. The server extracts the user id from the token to authenticate the request and scope data access — you never pass a user id explicitly.

### Data access control

* **Doctors** can access only their own resources (their appointments, recordings, transcriptions, notes, and documents). Accessing another user's resource returns `403 Forbidden`.
* **Admin** roles have elevated, system-level access (special permissions).

### Subscription requirements

Some actions require an active subscription or trial — notably **creating appointments** and **AI note generation**. If your trial or subscription has lapsed, `POST /api/appointments/add` returns `403` with a German message. Check your subscription status in the [dashboard](https://app.medisync.me).

## Error handling

Error responses are JSON, but the shape depends on the layer that produced them:

* **Auth middleware** (missing/invalid/revoked token) uses a `message` field.
* **Route handlers** (validation, not-found, ownership) use an `error` field.

<CodeGroup>
  ```json 401 Missing or invalid token theme={null}
  {
    "success": false,
    "message": "Unauthorized"
  }
  ```

  ```json 401 Session revoked (signed in elsewhere) theme={null}
  {
    "success": false,
    "message": "Session ended on this device because you signed in elsewhere.",
    "code": "SESSION_REVOKED"
  }
  ```

  ```json 403 Forbidden (not the resource owner) theme={null}
  {
    "success": false,
    "error": "Forbidden"
  }
  ```
</CodeGroup>

<Note>
  The API does not return the invented, English error `code` values shown in some older examples (e.g. `AUTH_REQUIRED`). Branch on the **HTTP status code** and the presence of `message` / `error` / `code` fields shown above.
</Note>

## Token management

### Expiration

| Token            | Lifetime |
| ---------------- | -------- |
| Standard         | 24 hours |
| `remember: true` | 7 days   |

### Handling expired tokens

When you receive a `401`:

1. Re-authenticate with `POST /api/login` to obtain a new token.
2. Retry the original request with the new token.

Accounts may be signed in on multiple devices; signing in beyond the device cap evicts the least-recently-active session, whose token then returns `401` with `code: "SESSION_REVOKED"`.

### Security best practices

<CardGroup cols={2}>
  <Card title="Token storage" icon="database">
    * Store tokens securely (encrypted where possible)
    * Never expose tokens in URLs or logs
    * Clear tokens on logout
  </Card>

  <Card title="Network security" icon="shield-halved">
    * Always use HTTPS / WSS
    * Validate TLS certificates
    * Monitor for unusual access patterns
  </Card>
</CardGroup>

## Rate limiting

Login is rate limited to protect against brute-force attempts:

| Endpoint          | Limit       | Window     | Key           |
| ----------------- | ----------- | ---------- | ------------- |
| `POST /api/login` | 10 attempts | 15 minutes | Email address |

Repeated failed attempts for the same email are temporarily blocked; standard `RateLimit-*` headers (and `Retry-After` on `429`) are returned.

## Next steps

<CardGroup cols={2}>
  <Card title="API Reference" icon="code" href="/api-reference/introduction">
    Explore the Dashboard API endpoints.
  </Card>

  <Card title="Login endpoint" icon="key" href="/api-reference/auth/login">
    Full reference for the login endpoint.
  </Card>
</CardGroup>
