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

# Authentication

> How to generate a one-time session code for the crypto widget.

### Before you begin

* **Credentials.** Contact Ripio to request your partner registration and obtain the `client_id` and `client_secret` that uniquely identify you as a Ripio customer. It is your responsibility to secure them.
* **A signing key for webhooks.** Issued alongside your credentials — see [Webhooks](/crypto-as-a-service/widget/webhooks).

<Note>
  This is the only widget endpoint you call directly, and it must be called from your **server**, never from the browser: `client_secret` should never reach the end user's device. Every other request — quotes, execution, portfolio, activity — is made by the widget itself on the user's behalf, so there is no other widget API for you to integrate against.
</Note>

### How a session starts

You never handle the user's session token. Your server asks Ripio for a **session code**, you hand that code to the widget, and the widget exchanges it for the session on its own as soon as it loads.

1. Your server calls `POST /auth` and receives a `session_code`.
2. You pass the code to the widget — as the `code` property when [embedding it](/crypto-as-a-service/widget/get-started/embedding), or in the URL fragment for a [WebView](/crypto-as-a-service/widget/get-started/webview).
3. The widget redeems the code, removes it from the URL and the page, and starts the user's session.

A session code works **once** and expires after **2 minutes**. That is what makes it safe to pass through a URL or a page attribute: by the time it could show up in a log, a browser history entry or a support screenshot, the widget has already used it.

### Generate a session code

Endpoint: `https://b2b-crypto-widget-api.sandbox.ripio.com/api/v1/auth`

Method: `POST` · Content-Type: `application/json`

| Field | Type | Description |
| - | - | - |
| `client_id` | *string* | Identifies your account. |
| `client_secret` | *string* | Your account's secret. Never send this from the browser. |
| `external_ref` | *string* | A unique, unrepeatable identifier for the user in your own system. Used to correlate webhooks and to map the widget session back to your user. |
| `requested_operations` | *array of string* (optional) | Narrow this session to a subset of `deposit`, `withdrawal`, `swap`, `yields`, `loan`, `buy`, `sell`. Omit it to grant everything your account has enabled. |

Request:

```bash theme={null}
curl \
  --location --request POST 'https://b2b-crypto-widget-api.sandbox.ripio.com/api/v1/auth' \
  --header 'Content-Type: application/json' \
  --data '{
    "client_id": "<client_id>",
    "client_secret": "<client_secret>",
    "external_ref": "<your-user-id>"
  }'
```

Response:

```json theme={null}
{
  "session_code": "k7Qe2Vn9Hc4yR1bT0sWmZpL8xA3dFgJ6uEoNiKqYtUw",
  "expires_in": 120
}
```

| Field | Description |
| - | - |
| `session_code` | Pass it to the widget to start the user's session. See [Embedding the widget](/crypto-as-a-service/widget/get-started/embedding). |
| `expires_in` | Seconds the code stays redeemable. |

<Warning>
  **Request the code right before you open the widget** — not when the user logs into your app, and never cached for later. It expires in 2 minutes and works only once: a code that was already used, or that you reuse for a second widget, starts no session. Mint a new one for every time the widget is opened.
</Warning>

Once redeemed, the session lasts **one hour** from the moment you called `POST /auth`. When it ends, the widget tells you so you can hand it a fresh code without reloading your page — see [Session lifecycle](/crypto-as-a-service/widget/get-started/session-lifecycle).

### Narrowing a session

```json theme={null}
{
  "client_id": "<client_id>",
  "client_secret": "<client_secret>",
  "external_ref": "<your-user-id>",
  "requested_operations": ["buy", "sell"]
}
```

This session can only buy and sell, regardless of what else your account has enabled — useful when you want a specific entry point of your app to expose a narrower widget than your account is capable of.

### Errors

| Cause | What happens |
| - | - |
| Invalid `client_id` or `client_secret` | `401`. The same generic error either way — Ripio doesn't distinguish "unknown client" from "wrong secret". |
| Too many requests for your `client_id` | `429`. The endpoint is rate-limited per account regardless of the caller's IP. |

See [Troubleshooting](/crypto-as-a-service/widget/troubleshooting) for the full error contract used across the widget's endpoints.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.