> ## Documentation Index
> Fetch the complete documentation index at: https://ibm-d95bab6e.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# IBM i Authentication

> Complete guide to IBM i HTTP authentication with token-based access, RSA encryption, and per-user connection pooling.

IBM i HTTP authentication enables secure, token-based access to the MCP server with per-user connection pooling. Clients authenticate with IBM i credentials to obtain Bearer tokens for subsequent API requests.

<Info>
  **When to use IBM i authentication:**

  * **Multi-user environments**: Each user gets their own connection pool with their credentials
  * **Production deployments**: Token-based auth with automatic expiry and session management
  * **Enhanced security**: Credentials encrypted during transmission using RSA/AES
  * **Audit trails**: Per-user tracking of database operations

  **When to use simpler auth:**

  * **Development**: Use shared `DB2i_USER`/`DB2i_PASS` credentials (no token auth needed)
  * **Single-user scenarios**: JWT or OAuth may be sufficient
</Info>

***

## How It Works

### Authentication Flow

```mermaid theme={null}
sequenceDiagram
    participant Client
    participant Server
    participant IBM i

    Client->>Server: 1. GET /api/v1/auth/public-key
    Server-->>Client: RSA Public Key

    Client->>Client: 2. Generate AES session key
    Client->>Client: 3. Encrypt credentials with session key
    Client->>Client: 4. Encrypt session key with RSA public key

    Client->>Server: 5. POST /api/v1/auth (encrypted payload)
    Server->>Server: 6. Decrypt session key with private key
    Server->>Server: 7. Decrypt credentials with session key

    Server->>IBM i: 8. Authenticate with decrypted credentials
    IBM i-->>Server: Authentication Success

    Server->>Server: 9. Create access token & connection pool
    Server-->>Client: Bearer Token

    Client->>Server: 10. API requests with Bearer token
    Server-->>Client: Authenticated responses
```

**Key Features:**

* **End-to-end encryption**: Credentials never transmitted in plain text
* **Per-user pools**: Each token gets its own dedicated DB2 connection pool
* **Token lifecycle**: Automatic expiry and cleanup of stale sessions
* **Key rotation**: Support for multiple keypairs for zero-downtime rotation

***

## Configuration

### Environment Variables

| Variable                             | Description                | Default      | Required |
| ------------------------------------ | -------------------------- | ------------ | -------- |
| `MCP_AUTH_MODE`                      | Must be set to `ibmi`      | `none`       | ✅ Yes    |
| `IBMI_HTTP_AUTH_ENABLED`             | Enable auth endpoints      | `false`      | ✅ Yes    |
| `IBMI_AUTH_KEY_ID`                   | Identifier for RSA keypair | (none)       | ✅ Yes    |
| `IBMI_AUTH_PRIVATE_KEY_PATH`         | Path to RSA private key    | (none)       | ✅ Yes    |
| `IBMI_AUTH_PUBLIC_KEY_PATH`          | Path to RSA public key     | (none)       | ✅ Yes    |
| `IBMI_AUTH_ALLOW_HTTP`               | Allow HTTP (dev only)      | `false`      | No       |
| `IBMI_AUTH_TOKEN_EXPIRY_SECONDS`     | Token lifetime             | `3600` (1hr) | No       |
| `IBMI_AUTH_CLEANUP_INTERVAL_SECONDS` | Cleanup interval           | `300` (5min) | No       |
| `IBMI_AUTH_MAX_CONCURRENT_SESSIONS`  | Max sessions               | `100`        | No       |

<Info>
  **Complete Reference**: See the [IBM i Authentication Settings](/configuration#ibm-i-authentication-settings) section in the Configuration Reference for all available environment variables and their defaults.
</Info>

### Db2i Credentials: Important Notes

<Warning>
  **Common Pitfall**: When using IBM i HTTP authentication, you may encounter validation errors about `DB2i_USER` and `DB2i_PASS` even though the Bearer token provides authentication.

  **Solution**: Either **omit these variables entirely** from your `.env` file, or set them to placeholder values like `TOKEN_AUTH`.

  **Why this happens**: The validation schema requires these fields to be either undefined or have non-empty values. Empty strings (`DB2i_USER=""`) fail validation. When using token authentication, the Bearer token supplies user credentials, so `DB2i_USER` and `DB2i_PASS` are not used.
</Warning>

<Tabs>
  <Tab title="Option 1: Omit Variables (Recommended)">
    ```bash theme={null}
    # .env for IBM i HTTP Authentication

    # Authentication Mode
    MCP_AUTH_MODE=ibmi
    IBMI_HTTP_AUTH_ENABLED=true

    # Encryption Keys
    IBMI_AUTH_KEY_ID=production
    IBMI_AUTH_PRIVATE_KEY_PATH=secrets/private.pem
    IBMI_AUTH_PUBLIC_KEY_PATH=secrets/public.pem

    # IBM i Connection (host only, no credentials)
    DB2i_HOST=ibmi-prod.company.com
    DB2i_PORT=8076
    DB2i_IGNORE_UNAUTHORIZED=false

    # DO NOT INCLUDE DB2i_USER or DB2i_PASS
    # Token authentication provides user credentials
    ```

    **This is the cleanest approach**: Variables are completely absent from the configuration.
  </Tab>

  <Tab title="Option 2: Placeholder Values">
    ```bash theme={null}
    # .env for IBM i HTTP Authentication

    # Authentication Mode
    MCP_AUTH_MODE=ibmi
    IBMI_HTTP_AUTH_ENABLED=true

    # Encryption Keys
    IBMI_AUTH_KEY_ID=production
    IBMI_AUTH_PRIVATE_KEY_PATH=secrets/private.pem
    IBMI_AUTH_PUBLIC_KEY_PATH=secrets/public.pem

    # IBM i Connection
    DB2i_HOST=ibmi-prod.company.com
    DB2i_PORT=8076
    DB2i_IGNORE_UNAUTHORIZED=false

    # Placeholders (not used during token auth)
    DB2i_USER=TOKEN_AUTH
    DB2i_PASS=TOKEN_AUTH
    ```

    **Why this works**: Validation passes because values are non-empty, but they're never used since token auth provides real credentials.
  </Tab>
</Tabs>

<Note>
  **Reference**: See [GitHub Issue #77](https://github.com/IBM/ibmi-mcp-server/issues/77) for the original discussion of this validation behavior.
</Note>

***

## Setup: RSA Encryption Keys

IBM i authentication requires RSA keypairs to protect credentials during transmission. The authentication flow uses RSA and AES encryption to securely exchange IBM i credentials between clients and the server.

<Steps>
  <Step title="Create Secrets Directory">
    Create a dedicated directory for storing encryption keys:

    ```bash theme={null}
    mkdir -p secrets
    ```

    <Tip>
      Store the `secrets/` directory outside of version control. Add it to your `.gitignore` file.
    </Tip>
  </Step>

  <Step title="Generate RSA Private Key">
    Generate a 2048-bit RSA private key:

    ```bash theme={null}
    openssl genpkey -algorithm RSA \
      -out secrets/private.pem \
      -pkeyopt rsa_keygen_bits:2048
    ```

    **What this does:**

    * Creates a new RSA private key with 2048-bit encryption strength
    * Saves it to `secrets/private.pem`
    * This key will be used by the server to decrypt credentials sent by clients
  </Step>

  <Step title="Extract Public Key">
    Extract the corresponding public key from the private key:

    ```bash theme={null}
    openssl rsa -pubout \
      -in secrets/private.pem \
      -out secrets/public.pem
    ```

    **What this does:**

    * Derives the public key from your private key
    * Saves it to `secrets/public.pem`
    * Clients use this public key to encrypt credentials before sending them to the server
  </Step>

  <Step title="Set Secure File Permissions">
    Restrict access to your private key:

    ```bash theme={null}
    # Make private key readable only by owner
    chmod 600 secrets/private.pem

    # Public key can be more permissive
    chmod 644 secrets/public.pem
    ```

    <Warning>
      **Critical Security Step**: The private key (`private.pem`) must be protected. Anyone with access to this file can decrypt client credentials.
    </Warning>
  </Step>

  <Step title="Configure Environment Variables">
    Add the keypair paths to your `.env` file:

    ```bash theme={null}
    # IBM i Authentication Keys
    IBMI_AUTH_KEY_ID=production
    IBMI_AUTH_PRIVATE_KEY_PATH=secrets/private.pem
    IBMI_AUTH_PUBLIC_KEY_PATH=secrets/public.pem
    ```

    **Key Configuration:**

    * `IBMI_AUTH_KEY_ID`: Identifier for this keypair (used for key rotation)
    * `IBMI_AUTH_PRIVATE_KEY_PATH`: Path to your private key file
    * `IBMI_AUTH_PUBLIC_KEY_PATH`: Path to your public key file
  </Step>
</Steps>

**How the Encryption Works:**

1. **Client requests public key** from server (`/api/v1/auth/public-key`)
2. **Client generates** a random AES-256-GCM session key
3. **Client encrypts** IBM i credentials with the session key
4. **Client encrypts** the session key with the server's RSA public key
5. **Server decrypts** the session key using its RSA private key
6. **Server decrypts** the credentials using the session key
7. **Server authenticates** against IBM i and issues an access token

<Note>
  **Key Rotation**: To rotate keys, generate a new keypair with a different `IBMI_AUTH_KEY_ID`. The server can support multiple keypairs simultaneously, allowing gradual migration without service interruption.
</Note>

***

## Start the Server

After configuring IBM i authentication and generating your RSA keys, start the MCP server with authentication enabled.

**Complete Configuration Example:**

```bash theme={null}
# .env file with IBM i HTTP Authentication
MCP_AUTH_MODE=ibmi
IBMI_HTTP_AUTH_ENABLED=true

# Encryption Keys
IBMI_AUTH_KEY_ID=production
IBMI_AUTH_PRIVATE_KEY_PATH=secrets/private.pem
IBMI_AUTH_PUBLIC_KEY_PATH=secrets/public.pem

# IBM i Connection (host only - no DB2i_USER/DB2i_PASS needed)
DB2i_HOST=ibmi-prod.company.com
DB2i_PORT=8076
DB2i_IGNORE_UNAUTHORIZED=false

# Server Settings
MCP_TRANSPORT_TYPE=http
MCP_HTTP_PORT=3010
MCP_LOG_LEVEL=info

# Security (production)
IBMI_AUTH_ALLOW_HTTP=false
IBMI_AUTH_TOKEN_EXPIRY_SECONDS=3600
```

**Start the Server:**

<Tabs>
  <Tab title="NPM Package">
    ```bash theme={null}
    # Set configuration file path
    export MCP_SERVER_CONFIG=.env

    # Start the server
    npx -y @ibm/ibmi-mcp-server@latest --transport http --tools ./tools
    ```

    You should see:

    ```
    ✓ IBM i HTTP authentication enabled
    ✓ Public key loaded from secrets/public.pem
    ✓ Private key loaded from secrets/private.pem
    ✓ Server ready!
      Transport: http
      Host: 127.0.0.1:3010
      Endpoint: http://127.0.0.1:3010/mcp
      Auth: IBM i HTTP (key_id: production)
    ```
  </Tab>

  <Tab title="Build from Source">
    ```bash theme={null}
    # From the repository root
    export MCP_SERVER_CONFIG=.env
    cd packages/server
    npm run start:http -- --tools ../../tools
    ```

    You should see:

    ```
    ✓ IBM i HTTP authentication enabled
    ✓ Public key loaded from secrets/public.pem
    ✓ Private key loaded from secrets/private.pem
    ✓ Server ready!
      Transport: http
      Host: 127.0.0.1:3010
      Endpoint: http://127.0.0.1:3010/mcp
      Auth: IBM i HTTP (key_id: production)
    ```
  </Tab>
</Tabs>

<Success>
  ✓ **Verify authentication is working:**

  Test the public key endpoint:

  ```bash theme={null}
  curl http://localhost:3010/api/v1/auth/public-key
  ```

  Should return:

  ```json theme={null}
  {
    "keyId": "production",
    "publicKey": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhki..."
  }
  ```

  If you see the public key, authentication is properly configured!
</Success>

<Warning>
  **Production HTTPS**: In production, ensure `IBMI_AUTH_ALLOW_HTTP=false` and use HTTPS. The server will reject HTTP authentication requests for security.
</Warning>

***

## Usage Examples

### Getting an Access Token

The repository includes a helper script to obtain authentication tokens: [`get-access-token.js`](https://github.com/IBM/ibmi-mcp-server/blob/main/get-access-token.js)

<Note>
  **Script Location**: The `get-access-token.js` script is included in the root of the [GitHub repository](https://github.com/IBM/ibmi-mcp-server/blob/main/get-access-token.js). Clone the repository or download this file to use the token helper.

  **What it does**: This script authenticates with your IBM i credentials and generates a Bearer token, then outputs a command to set the `IBMI_MCP_ACCESS_TOKEN` environment variable.
</Note>

```bash theme={null}
# Clone the repository if you haven't already
git clone https://github.com/IBM/ibmi-mcp-server.git
cd ibmi-mcp-server

# ONE-LINER: Generate token and set IBMI_MCP_ACCESS_TOKEN automatically
eval $(node get-access-token.js --quiet)

# Verify the token was set
echo $IBMI_MCP_ACCESS_TOKEN

# Alternative: View token details with verbose output
node get-access-token.js --verbose

# Alternative: Specify credentials explicitly
node get-access-token.js \
  --user myuser \
  --password mypass \
  --host my-ibmi-host \
  --quiet
```

<Tip>
  **Quick Setup**: The one-liner `eval $(node get-access-token.js --quiet)` does everything:

  1. Reads your IBM i credentials from `.env`
  2. Encrypts and sends them to the MCP server
  3. Receives the Bearer token
  4. Automatically sets `export IBMI_MCP_ACCESS_TOKEN=your-token`
  5. Token is now available in your shell session

  Use this token with any MCP client by including the header: `Authorization: Bearer $IBMI_MCP_ACCESS_TOKEN`
</Tip>

**Example Output:**

```bash theme={null}
$ eval $(node get-access-token.js --quiet)
$ echo $IBMI_MCP_ACCESS_TOKEN
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiTVlVU0VSIiwiaG9zdCI6...

# Token is now set and ready to use with MCP clients
```

**Common Options:**

| Option       | Short | Description                               | Default               |
| ------------ | ----- | ----------------------------------------- | --------------------- |
| `--user`     | `-u`  | IBM i username                            | `DB2i_USER` from .env |
| `--password` | `-p`  | IBM i password                            | `DB2i_PASS` from .env |
| `--host`     | `-h`  | IBM i host address                        | `DB2i_HOST` from .env |
| `--server`   |       | MCP server address                        | `localhost`           |
| `--port`     |       | MCP server port                           | `3010`                |
| `--https`    |       | Use HTTPS instead of HTTP                 | HTTP                  |
| `--verbose`  | `-v`  | Enable verbose output with metadata       | (quiet mode)          |
| `--quiet`    | `-q`  | Output only export command for shell eval | (normal mode)         |

<Accordion title="Advanced Options">
  For advanced use cases, the script supports additional configuration:

  | Option              | Description                                              |
  | ------------------- | -------------------------------------------------------- |
  | `--duration`        | Token duration in seconds                                |
  | `--pool-start`      | Initial connection pool size                             |
  | `--pool-max`        | Maximum connection pool size                             |
  | `--public-key-path` | Path to PEM-encoded server public key (skips HTTP fetch) |
  | `--key-id`          | Key identifier when using `--public-key-path`            |

  **Example with advanced options:**

  ```bash theme={null}
  node get-access-token.js \
    --server prod-mcp.company.com \
    --port 443 \
    --https \
    --duration 7200 \
    --quiet
  ```
</Accordion>

The script automatically:

* Loads IBM i credentials from `.env` with CLI fallback
* Fetches the server's public key (or uses local file with `--public-key-path`)
* Encrypts credentials client-side using RSA/AES
* Requests an access token from the MCP server
* Outputs the token (or export command in quiet mode)

**View Source**: See the full implementation at [`get-access-token.js`](https://github.com/IBM/ibmi-mcp-server/blob/main/get-access-token.js)

### Using the Token with MCP Clients

Once you have a token, configure your MCP client:

<Tabs>
  <Tab title="Python (Agno)">
    ```python theme={null}
    import asyncio
    import os
    from agno.agent import Agent
    from agno.tools.mcp import MCPTools, StreamableHTTPClientParams

    # Get access token from environment
    token = os.environ.get('IBMI_MCP_ACCESS_TOKEN')
    if not token:
        raise ValueError("IBMI_MCP_ACCESS_TOKEN not set")

    url = "http://localhost:3010/mcp"
    server_params = StreamableHTTPClientParams(
        url=url,
        headers={"Authorization": f"Bearer {token}"}
    )

    async def main():
        async with MCPTools(
            url=url,
            server_params=server_params,
            transport="streamable-http"
        ) as tools:
            agent = Agent(
                model="openai:gpt-4o",
                tools=[tools],
                name="ibmi-agent",
                show_tool_calls=True
            )
            await agent.aprint_response("What is the system status?")

    if __name__ == "__main__":
        asyncio.run(main())
    ```
  </Tab>

  <Tab title="Python (MCP SDK)">
    ```python theme={null}
    import asyncio
    import os
    from mcp import ClientSession
    from mcp.client.streamable_http import streamablehttp_client

    async def main():
        token = os.environ.get('IBMI_MCP_ACCESS_TOKEN')
        if not token:
            raise ValueError("IBMI_MCP_ACCESS_TOKEN not set")

        headers = {"Authorization": f"Bearer {token}"}

        async with streamablehttp_client(
            "http://localhost:3010/mcp",
            headers=headers
        ) as (read_stream, write_stream, _):
            async with ClientSession(read_stream, write_stream) as session:
                await session.initialize()

                # List tools
                tools = await session.list_tools()
                print(f"Tools: {[t.name for t in tools.tools]}")

                # Execute a tool
                result = await session.call_tool("system_status", {})
                print(result)

    if __name__ == "__main__":
        asyncio.run(main())
    ```
  </Tab>

  <Tab title="Claude Desktop">
    ```json theme={null}
    {
      "mcpServers": {
        "ibmi-mcp": {
          "url": "http://localhost:3010/mcp",
          "type": "http",
          "headers": {
            "Authorization": "Bearer YOUR_ACCESS_TOKEN_HERE"
          }
        }
      }
    }
    ```
  </Tab>

  <Tab title="VSCode">
    ```json theme={null}
    {
      "servers": {
        "ibmiMcp": {
          "type": "http",
          "url": "http://localhost:3010/mcp",
          "headers": {
            "Authorization": "Bearer YOUR_ACCESS_TOKEN_HERE"
          }
        }
      }
    }
    ```
  </Tab>
</Tabs>

***

## Security Best Practices

<AccordionGroup>
  <Accordion title="Production Deployment" icon="shield-check">
    * **Always use HTTPS**: Set `IBMI_AUTH_ALLOW_HTTP=false`
    * **Rotate keys regularly**: Generate new keypairs every 90-180 days
    * **Use strong key sizes**: 2048-bit minimum, 4096-bit recommended for high-security environments
    * **Monitor key access**: Enable file auditing on the `secrets/` directory
    * **Backup keys securely**: Store encrypted backups in a secrets management system
  </Accordion>

  <Accordion title="File Permissions" icon="lock">
    * **Private key**: `chmod 600 secrets/private.pem` (owner read/write only)
    * **Public key**: `chmod 644 secrets/public.pem` (world-readable is safe)
    * **Secrets directory**: `chmod 700 secrets/` (owner access only)
    * **Owner**: Ensure files are owned by the service account running the MCP server
  </Accordion>

  <Accordion title="Version Control" icon="code-branch">
    * **Never commit keys**: Add `secrets/` to `.gitignore`
    * **Never commit `.env`**: Environment files often contain paths to secrets
    * **Use environment-specific keys**: Different keypairs for dev/staging/production
    * **Document setup process**: Include key generation in deployment documentation
  </Accordion>

  <Accordion title="Secrets Management" icon="vault">
    For production environments, consider using a secrets management system:

    * **AWS Secrets Manager**: Store keys in encrypted AWS vault
    * **HashiCorp Vault**: Centralized secrets management with audit logs
    * **Azure Key Vault**: Microsoft's cloud-based secrets storage
    * **Kubernetes Secrets**: For containerized deployments

    Update `IBMI_AUTH_PRIVATE_KEY_PATH` to reference the mounted secret location.
  </Accordion>

  <Accordion title="Network Security" icon="network-wired">
    * **HTTPS Only**: Never allow `IBMI_AUTH_ALLOW_HTTP=true` in production
    * **Firewall Rules**: Restrict access to auth endpoints
    * **Rate Limiting**: Configure rate limits on authentication endpoints
    * **IP Whitelisting**: Restrict auth access to known client IPs when possible
  </Accordion>
</AccordionGroup>

***

## Troubleshooting

<AccordionGroup>
  <Accordion title="Validation Error: DB2i_USER and DB2i_PASS Required">
    **Symptom**: Server fails to start with error requiring `DB2i_USER` and `DB2i_PASS` even though you're using token authentication.

    **Solution**: Either completely omit these variables from your `.env` file, or set them to placeholder values like `TOKEN_AUTH`. Do not use empty strings (`DB2i_USER=""`).

    See the [Configuration](#configuration) section above for detailed examples.

    **Why**: Validation requires these fields to be either undefined or have non-empty values. When using token auth, credentials come from the Bearer token, not environment variables.
  </Accordion>

  <Accordion title="401 Unauthorized When Using Token">
    **Possible causes:**

    * Token has expired (check `IBMI_AUTH_TOKEN_EXPIRY_SECONDS`)
    * Token was obtained from a different server instance
    * Authorization header missing or malformed

    **Check:**

    ```bash theme={null}
    # Verify header format
    curl -H "Authorization: Bearer YOUR_TOKEN" http://localhost:3010/mcp

    # Get a fresh token
    node get-access-token.js --verbose
    ```
  </Accordion>

  <Accordion title="Encryption Key Errors">
    **Symptom**: Server fails to start or auth requests fail with encryption errors.

    **Solutions:**

    * Verify file paths in `.env` are correct
    * Check file permissions: `ls -la secrets/`
    * Ensure private key is valid: `openssl rsa -in secrets/private.pem -check`
    * Regenerate keypair if corrupted
  </Accordion>

  <Accordion title="Connection Pool Exhaustion">
    **Symptom**: "Max concurrent sessions reached" errors.

    **Solutions:**

    * Increase `IBMI_AUTH_MAX_CONCURRENT_SESSIONS`
    * Reduce `IBMI_AUTH_TOKEN_EXPIRY_SECONDS` to clean up idle sessions faster
    * Monitor active sessions and adjust cleanup interval
  </Accordion>
</AccordionGroup>

***

## Authentication Endpoints

When enabled (`IBMI_HTTP_AUTH_ENABLED=true`), the server provides these endpoints:

| Endpoint                  | Method | Description                                                            |
| ------------------------- | ------ | ---------------------------------------------------------------------- |
| `/api/v1/auth/public-key` | GET    | Retrieve server's RSA public key for client-side encryption            |
| `/api/v1/auth`            | POST   | Authenticate with encrypted IBM i credentials and receive Bearer token |
| `/healthz`                | GET    | Health check endpoint (no authentication required)                     |

For detailed API specifications, see the [API Reference](/api/auth-endpoints).

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Configuration Reference" icon="gear" href="/configuration">
    Explore all configuration options for the MCP server
  </Card>

  <Card title="Client Integrations" icon="plug" href="/clients/overview">
    Connect Claude Desktop, VSCode, Cursor, and other MCP clients
  </Card>

  <Card title="SQL Tools" icon="database" href="/sql-tools/overview">
    Create custom SQL operations for authenticated users
  </Card>

  <Card title="Production Deployment" icon="server" href="/deployment/production">
    Deploy with Docker, HTTPS, and secrets management
  </Card>
</CardGroup>
