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

# Authentication

> Learn how to authenticate with Rise using the SDK

# Authentication

<Warning>
  **Two things have to be in place before your first authenticated call**, and the API returns a `403` even with correct code if either is missing:

  1. Rise has to enable your company for B2B API access in the environment you're calling. Staging and production are enabled separately, so a request for one does not carry to the other.
  2. The wallet you authenticate with has to hold an authorized role (Owner, Payer, or Treasurer) on your RiseID.

  Both are walked through in [Getting API Access](/authentication/api-access). Set them up there first, then come back here for the handshake itself.
</Warning>

Rise implements a dual authentication system to ensure maximum security for your integrations. JWT tokens provide session management for all API operations, while SIWE (Sign-In with Ethereum) is required to obtain JWT tokens and adds blockchain-based verification for sensitive transactions. The Rise SDK simplifies this process by handling both authentication layers automatically.

<CardGroup cols={2}>
  <Card title="SIWE Authentication" icon="key">
    Use your wallet and private key for automatic authentication
  </Card>

  <Card title="JWT Authentication" icon="shield">
    Use a pre-generated JWT token for direct API access
  </Card>
</CardGroup>

## Authentication Layers

Rise's dual authentication system consists of two complementary layers:

### **JWT Authentication Layer**

* **Session management**: Provides secure session management for all API operations
* **User identity**: Verifies user identity and permissions
* **Access control**: Handles API access control and rate limiting
* **Token-based**: Uses JWT tokens for secure communication

### **SIWE Authentication Layer**

* **JWT token generation**: Required to obtain JWT tokens for API access
* **Blockchain verification**: Uses cryptographic wallet signing for authentication
* **Enhanced security**: Provides additional security for sensitive operations
* **Wallet-based**: Uses your wallet credentials for comprehensive access
* **Immutable proof**: Creates immutable proof of user intent and authorization
* **Write operations**: Required for the majority of write operations in Rise

## API Authentication Requirements

Different API endpoints require different levels of authentication:

### **JWT Authentication (Read Operations)**

* User profile information (`/me`)
* Company information (`/companies`)
* Team management (`/teams`)
* Balance queries (`/entity-balance`)
* Transaction history (`/transactions`)

**Note**: JWT tokens are obtained through SIWE authentication

### **Dual Authentication (Sensitive Operations)**

* Payment processing (`/payments`)
* Withdrawals (`/withdrawals`)
* Manager invites (`/invites`)
* Company settings updates
* High-value transactions

**Note**: These operations require both JWT (obtained via SIWE) and additional SIWE signing

<Note>
  **SDK Recommendation**: Use the Rise SDK for automatic authentication handling. The SDK will use SIWE to generate JWT tokens and automatically add SIWE signing when required for sensitive operations.
</Note>

## Authentication Flows

Whether you use the SDK or call the API directly, the same handshake runs underneath: ask Rise for a SIWE message, sign it with your wallet, then exchange the signature for a JWT. The SDK does all three steps for you.

```mermaid theme={null}
sequenceDiagram
    participant App as Your integration
    participant Wallet as API wallet
    participant Rise as Rise API

    App->>Rise: GET /v2/auth/siwe (wallet, riseid)
    Note over Rise: Checks the wallet's on-chain role on the RiseID
    Rise-->>App: 200 with data.siwe (the message to sign)
    App->>Wallet: Sign the SIWE message
    Wallet-->>App: signature
    App->>Rise: POST /v2/auth/verify (message, sig, nonce)
    Rise-->>App: 200 with data.jwt
    App->>Rise: Any endpoint with Authorization: Bearer JWT
    Rise-->>App: 200
```

The JWT is valid for 24 hours. The SDK refreshes it for you; if you drive the handshake yourself, re-run it when the token expires.

### SIWE Authentication Flow

The SDK manages the complete SIWE authentication process:

<Steps>
  <Step title="Initialize SDK">
    Configure the SDK with your Rise ID and private key
  </Step>

  <Step title="Automatic JWT Generation">
    SDK generates SIWE message, signs it, and obtains JWT token
  </Step>

  <Step title="Token Management">
    SDK automatically handles JWT token renewal
  </Step>

  <Step title="API Access">
    Execute API calls with automatic authentication handling
  </Step>
</Steps>

### JWT Authentication Flow

For integrations using pre-generated JWT tokens:

<Steps>
  <Step title="Obtain JWT Token">
    Retrieve JWT token from your existing authentication system
  </Step>

  <Step title="Initialize SDK">
    Configure the SDK with your JWT token
  </Step>

  <Step title="API Access">
    Execute API calls with automatic JWT header inclusion
  </Step>

  <Step title="Token Management">
    Handle token expiration through manual renewal or token refresh
  </Step>
</Steps>

## Understanding Authentication

### How SIWE Authentication Works

```javascript theme={null}
const { ethers } = require('ethers');

// Production: https://integrations-api.riseworks.io
// Staging:    https://integrations-api.staging-riseworks.io
const BASE_URL = 'https://integrations-api.riseworks.io';

async function understandSIWEAuthentication() {
  try {
    const wallet = new ethers.Wallet(process.env.WALLET_PRIVATE_KEY);

    // Step 1: Ask Rise for a SIWE message. The wallet address and your
    // personal (user) RiseID both go in the query string.
    const siweResponse = await fetch(
      `${BASE_URL}/v2/auth/siwe?wallet=${wallet.address}&riseid=${process.env.RISE_ID}`
    );

    if (!siweResponse.ok) {
      const { data } = await siweResponse.json();
      throw new Error(`SIWE request failed (${siweResponse.status}): ${data}`);
    }

    const siweData = await siweResponse.json();
    const message = siweData.data.siwe;

    // Step 2: Sign the message with your private key
    const signature = await wallet.signMessage(message);

    // Step 3: Read the nonce back out of the signed message
    const nonce = message.match(/Nonce: (.+)/)?.[1]?.trim();

    // Step 4: Exchange the signature for a JWT
    const verifyResponse = await fetch(`${BASE_URL}/v2/auth/verify`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ message, sig: signature, nonce })
    });

    const jwtData = await verifyResponse.json();
    const jwtToken = jwtData.data.jwt;

    console.log('JWT token generated:', jwtToken);
    return jwtToken;

  } catch (error) {
    console.error('SIWE authentication failed:', error.message);
    throw error;
  }
}

// This shows how SIWE authentication works internally
// The Rise SDK handles this automatically for you
const jwtToken = await understandSIWEAuthentication();
```

### How JWT Token Authentication Works

```javascript theme={null}
async function understandJWTUsage(jwtToken) {
  try {
    // Use JWT token for API calls
    const response = await fetch('https://integrations-api.riseworks.io/v2/me', {
      method: 'GET',
      headers: {
        'Authorization': `Bearer ${jwtToken}`,
        'Content-Type': 'application/json'
      }
    });

    const userData = await response.json();
    console.log('User data:', userData);
    return userData;

  } catch (error) {
    console.error('API call failed:', error.message);
    throw error;
  }
}

// This shows how JWT authentication works internally
// The Rise SDK handles this automatically for you
const userData = await understandJWTUsage(jwtToken);
```

## SDK Configuration Options

The Rise SDK provides two configuration options to access the APIs:

### **Using Rise ID and Private Key**

* **Automatic JWT generation**: SDK handles SIWE authentication automatically
* **Comprehensive access**: Full access to all API operations
* **Session management**: Automatic JWT token renewal
* **Wallet-based**: Uses your wallet credentials for authentication

### **Using JWT Token Only**

* **Pre-generated tokens**: Use existing JWT tokens for authentication
* **Basic access**: Access to read operations and basic integrations
* **Simple setup**: Direct API access without wallet signing
* **Limited scope**: Cannot perform sensitive operations requiring SIWE

## Quick Start with SDK

### Using Rise ID Authentication (Recommended)

```javascript theme={null}
const { RiseApiClient } = require('@riseworks/sdk');

// Initialize with Rise ID and private key for comprehensive API access
const client = new RiseApiClient({
  riseIdAuth: {
    riseId: process.env.RISE_ID,
    privateKey: process.env.WALLET_PRIVATE_KEY
  }
});

// SDK automatically handles both JWT and SIWE authentication
const user = await client.me.get();
console.log('Authenticated as:', user.data.name);
```

### Using JWT Token Authentication

```javascript theme={null}
const { RiseApiClient } = require('@riseworks/sdk');

// Note: You need to obtain the JWT token manually through SIWE authentication
// or from your existing authentication system before using this approach
// Initialize with JWT token for basic API access
// To get JWT: Use SIWE authentication first, then extract the JWT token
const client = new RiseApiClient({
  jwtToken: process.env.JWT_TOKEN
});

// Ready for read-only operations
const user = await client.me.get();
console.log('Authenticated as:', user.data.name);
```

```javascript theme={null}
const { ethers } = require('ethers');

const BASE_URL = 'https://integrations-api.riseworks.io';

async function generateJwtManually() {
  try {
    const wallet = new ethers.Wallet(process.env.WALLET_PRIVATE_KEY);

    // Step 1: Get a SIWE message
    const siweResponse = await fetch(
      `${BASE_URL}/v2/auth/siwe?wallet=${wallet.address}&riseid=${process.env.RISE_ID}`
    );

    const siweData = await siweResponse.json();
    const message = siweData.data.siwe;

    // Step 2: Sign it, then read the nonce back out of the message
    const signature = await wallet.signMessage(message);
    const nonce = message.match(/Nonce: (.+)/)?.[1]?.trim();

    // Step 3: Verify the signature and get the JWT
    const verifyResponse = await fetch(`${BASE_URL}/v2/auth/verify`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ message, sig: signature, nonce })
    });

    const jwtData = await verifyResponse.json();
    const jwtToken = jwtData.data.jwt;

    console.log('Manually generated JWT token:', jwtToken);
    return jwtToken;

  } catch (error) {
    console.error('JWT generation failed:', error.message);
    throw error;
  }
}

// Usage
const jwtToken = await generateJwtManually();
```

### JWT Token Management

```javascript theme={null}
// Store JWT token securely
const jwtToken = await client.getJwtToken();

// Use JWT token for subsequent API calls
const jwtClient = new RiseApiClient({
  jwtToken: jwtToken
});

// Verify JWT token validity
const isValid = await client.isJwtValid();
console.log('JWT token valid:', isValid);

// Refresh JWT token when needed
const newToken = await client.refreshJwtToken();
console.log('New JWT token:', newToken);
```

<Note>
  **SDK Recommendation**: Use the SDK's automatic JWT generation for simplicity. The SDK handles all the complexity of SIWE message generation, signing, and JWT token management for you.
</Note>

## SDK Features

### Automatic Token Management

```javascript theme={null}
// SDK automatically handles JWT token renewal
const client = new RiseApiClient({
  riseIdAuth: {
    riseId: process.env.RISE_ID,
    privateKey: process.env.WALLET_PRIVATE_KEY
  }
});

// SDK automatically generates new JWT tokens when needed
const user = await client.me.get(); // No manual token management required
```

### Token Generation

```javascript theme={null}
// Manually generate JWT token when necessary
const newToken = await client.generateJwtToken();
console.log('New JWT token:', newToken);
```

### Manual Token Refresh

```javascript theme={null}
// Manually refresh JWT token when necessary
const newToken = await client.refreshJwtToken();
console.log('New JWT token:', newToken);
```

### Token Validation

```javascript theme={null}
// Verify current JWT token validity
const isValid = await client.isJwtValid();
console.log('JWT valid:', isValid);
```

## Error Handling

The SDK provides comprehensive error handling for authentication scenarios:

```javascript theme={null}
const { RiseApiClient } = require('@riseworks/sdk');

async function handleAuthenticationErrors() {
  try {
    const client = new RiseApiClient({
      riseIdAuth: {
        riseId: process.env.RISE_ID,
        privateKey: process.env.WALLET_PRIVATE_KEY
      }
    });

    const user = await client.me.get();
    console.log('Success:', user.data);

  } catch (error) {
    if (error.message.includes('Rise ID and private key are required')) {
      console.error('Missing credentials - verify your environment variables');
    } else if (error.message.includes('Invalid Rise ID address')) {
      console.error('Invalid Rise ID format - should be 0x + 40 hex characters');
    } else if (error.message.includes('Invalid private key')) {
      console.error('Invalid private key format - should be 0x + 64 hex characters');
    } else if (error.message.includes('401')) {
      console.error('Authentication failed - verify your credentials');
    } else if (error.message.includes('403')) {
      console.error('Permission denied - verify your role permissions');
    } else {
      console.error('Unexpected error:', error.message);
    }
  }
}
```

## Common Error Scenarios

| Response                                                            | What it means                                                                                                                        | How to fix                                                                                                                                                                                   |
| ------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `404` `No entity found with riseid <id>`                            | The `riseid` isn't a user RiseID: it carries a network prefix (`arb4:`), is a `us-`/`co-`/`te-` nanoid, or is a company/team RiseID. | Send the bare `0x` user RiseID with the prefix stripped. See [Finding your RiseID](/authentication/api-access#finding-your-riseid).                                                          |
| `400` `Wallet address is required` / `riseid is required`           | `GET /v2/auth/siwe` was called without the `wallet` or `riseid` query param.                                                         | Pass both: `/v2/auth/siwe?wallet=<0x>&riseid=<0x>`.                                                                                                                                          |
| `403` `Wallet <addr> is not an authorized member of RiseID <id>...` | The wallet you're signing with holds no Owner, Payer, or Treasurer role on that RiseID.                                              | Authorize the wallet on your RiseID, wait for the on-chain transaction to confirm, then retry. See [Authorize your API wallet](/authentication/api-access#authorize-your-api-wallet).        |
| `403` `Company is not enabled for B2B API access`                   | Your company isn't enabled for the B2B API in this environment.                                                                      | Ask Rise to enable it for the environment you're calling. Staging and production are separate. See [Enable your company](/authentication/api-access#enable-your-company-for-b2b-api-access). |
| `401 Unauthorized`                                                  | The JWT is missing, expired, or invalid.                                                                                             | Re-run the SIWE handshake for a fresh token. The SDK does this for you.                                                                                                                      |
| `Invalid Rise ID address`                                           | Rise ID isn't in the right format.                                                                                                   | A Rise ID starts with `0x` and is 42 characters.                                                                                                                                             |
| `Invalid private key`                                               | Private key isn't in the right format.                                                                                               | A private key starts with `0x` and is 66 characters.                                                                                                                                         |

## Security Best Practices

### Recommended Practices:

* **Use environment variables** for all sensitive data
* **Use secondary wallets** for API operations
* **Implement comprehensive error handling**

### Security Considerations:

* **Never store private keys in code**
* **Never commit credentials to version control**
* **Avoid using main wallets** with significant funds for API operations
* **Never ignore authentication errors**

## Next Steps

<CardGroup cols={2}>
  <Card title="Private Keys Guide" icon="user-shield" href="/authentication/private-keys">
    Learn how to get and use private keys
  </Card>

  <Card title="Secondary Wallets" icon="wallet" href="/security/secondary-wallets">
    Use dedicated wallets for API operations
  </Card>

  <Card title="SDK Examples" icon="code" href="/sdk/examples">
    See more SDK usage examples
  </Card>

  <Card title="Security Best Practices" icon="shield" href="/security/best-practices">
    Comprehensive security guidelines
  </Card>
</CardGroup>

<Note>
  **Ready to integrate?** Review our [Quickstart Guide](/quickstart) to begin using the Rise SDK with authentication.
</Note>
