# Authentication

The ForePaaS API uses different authentication methods depending on the endpoint type.

{% hint style="warning" %}
**Security Notice:** Never expose your API key or private key in client-side code, version control, or public repositories. Store them securely using environment variables or a secrets management service.
{% endhint %}

## Authentication Matrix

Different endpoints require different authentication methods:

| Endpoint Type                 | Authentication Required | Headers Needed                                       |
| ----------------------------- | ----------------------- | ---------------------------------------------------- |
| **Public Endpoints**          | None                    | No authentication headers                            |
| **Merchant Signed Endpoints** | API Key + RSA Signature | `X-API-KEY`, `X-Signature`, `X-Timestamp`, `X-Nonce` |
| **User Session Endpoints**    | JWT Bearer Token        | `Authorization: Bearer <token>`                      |

**Examples by Type:**

**Public Endpoints (No Auth):**

* `GET /api/market/openapi/category`
* `GET /api/market/openapi/market/list`
* `GET /api/market/openapi/{marketId}/outcome`
* `POST /api/market/query/getTopHolders`
* `GET /api/order/activity/query-market-activity`
* `GET /api/market/query/{marketId}/market-process`

**Merchant Signed Endpoints (API Key + Signature):**

* `POST /api/user/openapi/authorize` - Returns JWT token for user endpoints

**User Session Endpoints (JWT Bearer Token):**

* All endpoints after authorization (positions, orders, notifications, etc.)
* JWT token obtained from `/api/user/openapi/authorize`
* Token format: `Authorization: Bearer <token>`

## Authentication Methods

The ForePaaS API uses a two-layer authentication approach for maximum security:

| Component         | Purpose                     | Location               | Format                                     |
| ----------------- | --------------------------- | ---------------------- | ------------------------------------------ |
| **API Key**       | Identifies your application | `X-API-KEY` header     | String (provided by ForePaaS)              |
| **RSA Signature** | Proves request authenticity | `X-Signature` header   | Base64-encoded RSA-SHA256                  |
| **JWT Token**     | Authorizes user actions     | `Authorization` header | `Bearer <token>` (from authorize endpoint) |

### API Key

Your API key is a unique identifier for your application. It must be included in the `X-API-KEY` header of every request.

> **Key Management:** Treat your API key like a password. If compromised, contact your ForePaaS account manager immediately to rotate it.

### Signature

To ensure the integrity and authenticity of your requests, all API calls must be signed using your RSA private key. The signature is passed in the `X-Signature` header.

### Required request headers

All authenticated requests must include the following headers:

| Header         | Required | Description                                                   |
| -------------- | -------: | ------------------------------------------------------------- |
| `X-API-KEY`    |      Yes | Your API key.                                                 |
| `X-Signature`  |      Yes | Base64-encoded RSA-SHA256 signature.                          |
| `X-Timestamp`  |      Yes | Unix timestamp in milliseconds used in the signature content. |
| `X-Nonce`      |      Yes | Unique random string used in the signature content.           |
| `Content-Type` |      Yes | Must be `application/json` for signed JSON requests.          |

### Signature flow

**Step-by-step authentication process:**

| Step | Actor  | Action                                                                          |
| ---- | ------ | ------------------------------------------------------------------------------- |
| 1    | Client | Build `signContent` string (method, content-type, path, body, timestamp, nonce) |
| 2    | Client | Sign with RSA-SHA256 using private key                                          |
| 3    | Client | Base64-encode the signature                                                     |
| 4    | Client | Send request with headers: `X-API-KEY`, `X-Signature`, `X-Timestamp`, `X-Nonce` |
| 5    | Server | Receive request and extract headers                                             |
| 6    | Server | Rebuild `signContent` string from request                                       |
| 7    | Server | Verify signature using client's public key                                      |
| 8a   | Server | ✅ **If valid:** Return `2xx` response with data                                 |
| 8b   | Server | ❌ **If invalid:** Return `401 Unauthorized` error                               |

### Signature Generation Process

{% hint style="info" %}
**Timestamp Validation:** The API validates that the timestamp in your request is within 5 minutes of the server time. If your signature fails, ensure your system clock is synchronized.
{% endhint %}

{% hint style="success" %}
**Best Practice:** Generate a new nonce for each request using a cryptographically secure random number generator. Never reuse nonces.
{% endhint %}

### Code Examples

Here are examples of how to generate a signature in different languages:

{% tabs %}
{% tab title="Java" %}

```java
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;

public class SignatureUtil {

    public static String sign(String content, String privateKeyString) throws Exception {
        byte[] keyBytes = Base64.getDecoder().decode(privateKeyString);
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PrivateKey privateKey = keyFactory.generatePrivate(keySpec);

        Signature signature = Signature.getInstance("SHA256withRSA");
        signature.initSign(privateKey);
        signature.update(content.getBytes("UTF-8"));

        byte[] signed = signature.sign();
        return Base64.getEncoder().encodeToString(signed);
    }
}
```

{% endtab %}

{% tab title="Node.js" %}

```javascript
const crypto = require('crypto');

function generateSignature(method, path, body, timestamp, nonce, privateKey) {
  const contentType = 'application/json';
  const bodyString = body ? JSON.stringify(body) : '';
  
  const signContent = [
    method,
    contentType,
    path,
    bodyString,
    timestamp.toString(),
    nonce
  ].join('\n');

  const sign = crypto.createSign('SHA256');
  sign.update(signContent);
  sign.end();

  return sign.sign(privateKey, 'base64');
}

// Usage
const privateKey = `-----BEGIN PRIVATE KEY-----
Your Private Key Here
-----END PRIVATE KEY-----`;

const signature = generateSignature(
  'POST',
  '/api/user/openapi/authorize',
  { marchantUserId: 'mer016', userEmail: 'mer016@gmail.com' },
  Date.now(),
  crypto.randomBytes(16).toString('hex'),
  privateKey
);

console.log('Signature:', signature);
```

{% endtab %}

{% tab title="Python" %}

```python
import base64
import json
import time
import secrets
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.backends import default_backend

def generate_signature(method, path, body, timestamp, nonce, private_key_pem):
    """Generate RSA-SHA256 signature"""
    content_type = 'application/json'
    body_string = json.dumps(body) if body else ''
    
    sign_content = '\n'.join([
        method,
        content_type,
        path,
        body_string,
        str(timestamp),
        nonce
    ])

    private_key = serialization.load_pem_private_key(
        private_key_pem.encode(),
        password=None,
        backend=default_backend()
    )

    signature = private_key.sign(
        sign_content.encode('utf-8'),
        padding.PKCS1v15(),
        hashes.SHA256()
    )

    return base64.b64encode(signature).decode('utf-8')

# Usage
private_key_pem = '''-----BEGIN PRIVATE KEY-----
Your Private Key Here
-----END PRIVATE KEY-----'''

signature = generate_signature(
    'POST',
    '/api/user/openapi/authorize',
    {'marchantUserId': 'mer016', 'userEmail': 'mer016@gmail.com'},
    int(time.time() * 1000),
    secrets.token_hex(16),
    private_key_pem
)

print(f'Signature: {signature}')
```

{% endtab %}
{% endtabs %}

<details>

<summary><strong>Advanced: Debugging Signature Issues</strong></summary>

If you're experiencing signature validation errors, follow this debugging checklist:

1. **Print the signContent string** before signing to verify it matches the expected format
2. **Check for trailing newlines** or extra whitespace
3. **Verify the request path** doesn't include the domain
4. **Ensure the body JSON** matches exactly (no extra spaces, same key order)
5. **Confirm your private key format** is PKCS#8, not PKCS#1
6. **Test with a simple GET request** (empty body) first

Example debug output:

```
POST
application/json
/api/user/openapi/authorize
{"marchantUserId":"mer016","userEmail":"mer016@gmail.com"}
1704067200000
a1b2c3d4e5f6
```

</details>

{% hint style="danger" %}
**Common Mistake:** Including the domain (e.g., `https://apidev.forepass.org`) in the signature path will cause authentication to fail. Only use the path: `/api/user/openapi/authorize`
{% endhint %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.forepaas.org/getting-started/authentication.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
