> For the complete documentation index, see [llms.txt](https://docs.blerify.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.blerify.com/introduction/authentication.md).

# Authentication

This page shows you what a service account is, how to create one in the Portal, and how to trade its credentials for a bearer token you can use on every request. Every call to the Blerify API works this way, whether you're using Issuance, Verification, or Trust Registry.

## Prerequisites

* Admin access to the [Blerify Portal](https://portal.blerify.com/)

## What is a service account

A service account isn't a person. It's an identity your backend uses to call the Blerify API. It has nothing to do with any individual login, and it never goes through a human sign-in flow. You can limit a service account to a single product (Issuance or Verification), or give it roles across several products at once. The roles you assign decide what the account can actually do. Check each product's Portal Roles and Permissions page for the full list of available roles.

Authentication works through the OAuth 2.0 `client_credentials` grant, using `private_key_jwt` as the client authentication method ([RFC 7523](https://www.rfc-editor.org/rfc/rfc7523)). There's no shared client secret. Instead, your service account's private key signs a short-lived JWT assertion, and you trade that assertion for a bearer token.

## Create a service account

1. Log in to the [Blerify Portal](https://portal.blerify.com/) with an admin account.

<figure><picture><source srcset="/files/XdBoXstyVnVcIMVeYWZt" media="(prefers-color-scheme: dark)"><img src="/files/wR5mptDZMc7qpKAZfNic" alt=""></picture><figcaption></figcaption></figure>

2. Go to **Settings → Service Accounts**.

<figure><picture><source srcset="/files/cav5PAimDgjuQ9Koug8D" media="(prefers-color-scheme: dark)"><img src="/files/viZSRgCceVgQxu2unPPF" alt=""></picture><figcaption></figcaption></figure>

3. Click **Create Service Account**.

<figure><picture><source srcset="/files/vNSnNapcAVRkY5eBre2f" media="(prefers-color-scheme: dark)"><img src="/files/BQOiabCUM3BFM5qYj6jc" alt=""></picture><figcaption></figcaption></figure>

4. Fill in the account details:
   * **Name** — a descriptive identifier (e.g. `payments-integration`, `kyc-backend`)
   * **Description** — optional; what this account is used for
   * **Roles** — the permissions this account needs, scoped per product (e.g. `verifications.api`, `credentials.api`, `notifications.api`)
5. Click **Create**. The Portal generates a credentials JSON file and downloads it right away. **You can't get this file again**, so save it somewhere safe before you close the dialog.

<figure><picture><source srcset="/files/kowjnVfIS63x9a3lVXZN" media="(prefers-color-scheme: dark)"><img src="/files/jOAAPXlKftZ4CONpwkKP" alt=""></picture><figcaption></figcaption></figure>

## The credentials file

The downloaded JSON has everything you need to authenticate:

```json
{
  "type": "service_account",
  "organization_id": "your-organization-id",
  "client_id": "your-client-id",
  "private_key": "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----",
  "token_uri": "https://...",
  "iam_audience": "https://..."
}
```

| Field             | Used for                                                                                                                  |
| ----------------- | ------------------------------------------------------------------------------------------------------------------------- |
| `client_id`       | Identifies the service account. Sent as the `client_id` form field, and also used as `iss` and `sub` in the JWT assertion |
| `organization_id` | Sent as the `organization_id` form field                                                                                  |
| `private_key`     | Signs the JWT assertion (RS256)                                                                                           |
| `token_uri`       | The token endpoint you send the assertion to. Always read this from the file, since it can vary by account                |
| `iam_audience`    | The `aud` claim in the JWT assertion                                                                                      |

Keep the `private_key` secret. Treat this file like a password: don't commit it to source control, don't put it in client-side code, and don't log it anywhere.

## Get an access token

Build a short-lived JWT assertion signed with your private key, then send it to `token_uri`. Everything you need is already in the credentials file — copy the values as they are. The only things you generate yourself are the two timestamps and the `jti`.

**JWT assertion structure:**

```json
// header
{ "alg": "RS256", "typ": "JWT" }

// payload
{
  "iss": "<client_id from the credentials file>",
  "sub": "<client_id from the credentials file>",
  "aud": "<iam_audience from the credentials file>",
  "iat": 1700000000,
  "exp": 1700003600,
  "jti": "a-unique-uuid-v4"
}
```

The `jti` needs to be unique on every request, since it stops the token from being replayed. Keep the assertion short-lived: one hour is a good default.

**Token request:**

```bash
curl -X POST '<token_uri from the credentials file>' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -d 'client_id=<client_id from the credentials file>' \
  -d 'organization_id=<organization_id from the credentials file>' \
  -d 'client_assertion=<the signed JWT you just built>'
```

**Response:**

```json
{
  "access_token": "eyJ...",
  "token_type": "Bearer",
  "expires_in": 600
}
```

Read `expires_in` from the response instead of hardcoding a number, since it can change.

### Use a library instead of building from scratch

The official [`blerify/auth-php-client`](https://github.com/BlerifyPlatform/auth-php-client) package handles assertion signing, token caching, and renewal from a credentials JSON file. If you work in PHP, start there.

## Use the token

Put the token in the `Authorization` header of every API request:

```
Authorization: Bearer eyJ...
```

Cache the token and refresh it before `expires_in` runs out. If you request a new token on every call, you'll add latency and hit rate limits under load.

## Next steps

[**Get Started with Issuance**](/introduction-to-issuance/build/get-started.md): issue your first credential using a service account with the `credentials.api` role.

See also: [Get Started with Verification](/introduction-to-verification/build/get-started.md) · Full endpoint reference at <https://dev.blerify.com>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## 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, and the optional `goal` query parameter:

```
GET https://docs.blerify.com/introduction/authentication.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
