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

# Bring your own auth

> Use Para REST API with your own user authentication and a backend signing service

Para REST API authenticates your backend with `X-API-Key`. It does not authenticate end users, mint user JWTs, or run OTP, passkey, or OAuth flows for clients.

Use this pattern when your app already has its own login system and you want your backend to create and sign with Para wallets on behalf of those users.

<Info>
  Want users to **sign in through Para** with your own identity provider (OIDC / SSO) instead? That's [Custom OIDC](/v3/general/developer-portal-custom-oidc) — a client-side login method, distinct from this server-side pattern.
</Info>

```text theme={null}
[Mobile or web client] -> [Your auth and API server] -> [Para REST API]
                              |
                              | X-API-Key: sk_...
                              v
                         Create wallets
                         Sign transactions
                         Read transaction status
```

<Warning>
  Keep your Para API key on your server. Do not put it in a mobile app, web app, desktop app, or client-side config.
</Warning>

<Info>
  This is a partner-custodial signing pattern. Your backend decides when to ask Para to sign. The end user does not have a Para session in REST API v1.
</Info>

## When to use this

| Use REST with BYO auth when                                    | Use a Para SDK when                                                      |
| -------------------------------------------------------------- | ------------------------------------------------------------------------ |
| You already authenticate users in your own backend.            | You want Para to run the user auth flow.                                 |
| You need to support a client platform without a Para SDK.      | You need SDK wallet objects, adapters, or client-side signing libraries. |
| Your server should create wallets and submit signing requests. | Users should control signing from their own Para session.                |
| You can model access control in your backend.                  | You need client-side private-key export or SDK share handling.           |

## Walkthrough

### 1. Authenticate the user in your app

Use your existing auth system. Your backend should map the authenticated user to a stable internal ID, such as `user_123`.

The client never talks to Para directly in this pattern.

### 2. Create a REST wallet for that user

Create the wallet from your backend after signup or when the user first needs a wallet. Use your internal user ID as a `CUSTOM_ID`.

```bash create-wallet.sh theme={null}
curl -X POST "https://api.beta.getpara.com/v1/wallets" \
  -H "X-API-Key: $PARA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "EVM",
    "userIdentifier": "user_123",
    "userIdentifierType": "CUSTOM_ID"
  }'
```

Store the returned `id` as the Para wallet ID for your user.

### 3. Look up the wallet by identifier

If you need to recover the mapping, query wallets by the same identifier.

```bash lookup-wallet.sh theme={null}
curl "https://api.beta.getpara.com/v1/wallets?userIdentifier=user_123&userIdentifierType=CUSTOM_ID" \
  -H "X-API-Key: $PARA_API_KEY"
```

### 4. Sign from your backend

Your client asks your backend to perform an action. Your backend checks the user's session and authorization, then calls Para. The `requireUser` and `db` calls below stand in for your app's auth and storage.

```typescript server.ts theme={null}
app.post("/api/wallets/:walletId/sign-message", requireUser, async (req, res) => {
  const wallet = await db.wallets.findById(req.params.walletId);

  if (!wallet || wallet.userId !== req.user.id) {
    return res.status(404).json({ error: "Wallet not found" });
  }

  const paraRes = await fetch(
    `https://api.beta.getpara.com/v1/wallets/${wallet.paraWalletId}/sign-message`,
    {
      method: "POST",
      headers: {
        "X-API-Key": process.env.PARA_API_KEY!,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({ message: req.body.message }),
    }
  );

  if (!paraRes.ok) {
    return res.status(paraRes.status).json(await paraRes.json());
  }

  res.json(await paraRes.json());
});
```

For transaction broadcasts, store the returned `transactionId`. Your backend can poll transaction history or receive REST transaction webhooks and expose the latest status to the client.

## Claiming and ownership

REST-created wallets are pre-created wallets. They start project-controlled and can be claimed later by a Para user if your app supports a client-side claim flow.

Before claim, REST signing endpoints work with the wallet ID and API key. After claim, REST signing endpoints reject the wallet because it is user-owned. At that point, use client SDK flows for user-owned wallet actions.

If you created a wallet with `CUSTOM_ID` but later want the user to claim it with an email, phone, or OAuth identifier, update the unclaimed wallet first:

```bash update-identifier.sh theme={null}
curl -X PATCH "https://api.beta.getpara.com/v1/wallets/$WALLET_ID" \
  -H "X-API-Key: $PARA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "userIdentifier": "user@example.com",
    "userIdentifierType": "EMAIL"
  }'
```

The `wallet.pregen_claimed` webhook can help your backend reconcile ownership after claim.

## Limits

* REST API v1 has no end-user Para session, user JWT, or user-scoped REST token.
* REST API v1 does not run OTP, passkey, OAuth, or Para-branded auth on the client.
* REST API v1 does not provide a private-key export endpoint.
* REST signing stops after the wallet is claimed by a user.
* Client-side export and SDK share-management flows require the relevant Para SDK path.
