# Authenticating users with the portal API

### Overview

API key authentication allows you to automatically sign in users by including an authentication token in the URL. This is useful for:

* Creating magic login links
* Embedding quests in external applications
* Deep-linking directly to protected content

### How It Works

When a valid API key is provided as a query parameter in the URL, the system will:

1. Validate the key against our backend
2. If valid, automatically sign in the associated user
3. Redirect to the same URL but with the token removed (for security)
4. **Store the user session in a cookie**, allowing continued access without the API key

Once the user has been authenticated, **they remain signed in via the session cookie**, not the API key. This means:

* The API key is only needed for the initial authentication
* You can use very short expiration times for your API keys (even minutes or seconds)
* After authentication, the user has a normal session just like any other login method

### Generating API Keys

To generate an API key, use the External User Lookup API endpoint on your community's domain:

```
POST https://your-community-slug.domino.page/api/auth/external-lookup
```

> **Important:** Replace `your-community-slug` with your actual community slug (e.g., if your community is at `acme.domino.page`, use that domain for the API request).

#### Request Parameters

| Parameter             | Type   | Description                                                                                                          |
| --------------------- | ------ | -------------------------------------------------------------------------------------------------------------------- |
| `externalId`          | String | **Required**. The unique identifier for this user in your system                                                     |
| `keyName`             | String | Optional. A name for this API key (defaults to "External API Key for \[community]")                                  |
| `keyExpiresInDays`    | Number | Optional. How long the key should be valid in days (defaults to 30 days)                                             |
| `keyExpiresInSeconds` | Number | Optional. How long the key should be valid in seconds. Takes precedence over `keyExpiresInDays` if both are provided |

#### User Profile Data

You can pass user profile information to create or update the user:

| Parameter   | Type    | Description                                                                                                   |
| ----------- | ------- | ------------------------------------------------------------------------------------------------------------- |
| `name`      | String  | Display name for the user                                                                                     |
| `email`     | String  | User's email address                                                                                          |
| `imageUrl`  | String  | Profile picture URL (will be cached to our CDN)                                                               |
| `overwrite` | Boolean | When `true`, provided fields overwrite existing data. When `false` (default), only empty fields are populated |

#### Social Account Identifiers

You can link social accounts by providing their platform IDs:

| Parameter     | Type   | Description       |
| ------------- | ------ | ----------------- |
| `discordId`   | String | Discord user ID   |
| `twitterId`   | String | Twitter/X user ID |
| `telegramId`  | String | Telegram user ID  |
| `redditId`    | String | Reddit user ID    |
| `zealyUserId` | String | Zealy user ID     |

You can also provide usernames as supplementary data:

* `discordUsername`
* `twitterUsername`
* `telegramUsername`
* `redditUsername`

#### Wallet Data

You can link wallets to the user:

| Parameter | Type   | Description                                                     |
| --------- | ------ | --------------------------------------------------------------- |
| `wallet`  | Object | A single wallet: `{ walletAddress, type, network?, provider? }` |
| `wallets` | Array  | Array of wallet objects with the same structure                 |

Wallet object structure:

* `walletAddress` (String): The wallet address
* `type` (String): Wallet type - `SOLANA`, `EVM`, or `TON`
* `network` (String, optional): Network identifier
* `provider` (String, optional): Wallet provider

#### Response

```json
{
  "user": {
    "id": "user-id",
    "username": "username",
    // other user properties
  },
  "apiKey": {
    "id": "key-id",
    "key": "the-actual-api-key",
    "expiresAt": "2023-12-31T23:59:59Z"
  }
}
```

#### Example Request

```javascript
// Replace 'acme.domino.page' with your actual community domain
const response = await fetch('https://acme.domino.page/api/auth/external-lookup', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'x-api-key': 'your-domino-api-key'
  },
  body: JSON.stringify({
    externalId: 'user123',
    keyName: 'Login link for newsletter',
    keyExpiresInSeconds: 300 // Expires in 5 minutes
  })
});

const data = await response.json();
const apiKey = data.apiKey.key;
```

#### Example with User Profile Data

```javascript
const response = await fetch('https://acme.domino.page/api/auth/external-lookup', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'x-api-key': 'your-domino-api-key'
  },
  body: JSON.stringify({
    externalId: 'user123',
    // Profile data
    name: 'John Doe',
    email: 'john@example.com',
    imageUrl: 'https://example.com/avatars/john.png',
    // Social accounts
    discordId: '123456789012345678',
    discordUsername: 'johndoe#1234',
    twitterId: '987654321',
    // Wallets
    wallets: [
      { walletAddress: '0x1234...', type: 'EVM' },
      { walletAddress: 'abc123...', type: 'SOLANA' }
    ],
    // Set to true to update existing user data
    overwrite: true,
    // API key options
    keyExpiresInSeconds: 300
  })
});
```

### Using the API Key in URLs

To authenticate a user with an API key, include the key as an `authToken` query parameter in your community's domain:

```
https://acme.domino.page/quests?authToken=the-actual-api-key
```

When the user visits this URL, they will be:

1. Automatically authenticated
2. Redirected to the same URL without the token parameter
3. Granted a session cookie for continued access

### Security Considerations

* API keys are sensitive credentials and should be treated securely
* Each key is linked to a specific user and should not be shared
* **API keys can have very short expiration times** since they're only needed for initial authentication
* Consider using `keyExpiresInSeconds` for one-time use links with very short lifetimes (minutes or even seconds)
* The redirect ensures the token isn't stored in browser history
* After authentication, the normal session cookie security applies
