The server wallet authentication flow is designed to be idempotent — calling authenticate() multiple times with the same identity is safe and will reuse existing credentials when possible.
How It Works
authenticate()
│
├─ Token already in store? ──► Reuse it (no network call)
│
└─ No token?
│
├─ Derive public key from accessKey
├─ POST /auth/create (register identity)
├─ POST /auth/exchange (get access token)
└─ Store token ──► Return session
On the first call, the SDK:
- Generates or accepts an
accessKey (64-char hex string)
- Derives a public key from it
- Calls
create to register the identity with the backend
- Calls
exchange to obtain an access token
- Stores the token for future use
On subsequent calls with the same identity, the stored token is returned immediately.
Usage
import { ServerSignerClient } from '@abstraxn/server-signer';
const client = new ServerSignerClient({
apiKey: process.env.ABSTRAXN_API_KEY!,
});
const session = await client.authenticate({
userIdentity: 'merchant-backend-user-001',
accessKey: process.env.SERVER_WALLET_ACCESS_KEY, // optional on first run
userName: 'Merchant Backend',
userEmail: '[email protected]',
});
Parameters
| Parameter | Type | Required | Description |
|---|
userIdentity | string | Yes | Unique identifier for this server wallet user |
accessKey | string | No | 64-char hex key. If omitted on first run, the SDK generates one |
userName | string | No | Display name for the wallet user |
userEmail | string | No | Email for the wallet user |
Return Value
| Field | Type | Description |
|---|
didCreate | boolean | true if this was a new identity, false if reusing existing token |
accessToken | string | Current JWT access token |
accessKey | string | The 64-char hex access key (generated or provided) |
targetPublicKey | string | Public key derived from the access key |
organizationId | string | Organization ID for this wallet |
walletAddress | string | On-chain wallet address |
Access Key Management
The accessKey is the root secret for a server wallet identity. It is used to derive the public key that identifies the wallet on-chain.
If you lose the access key, you cannot recover the same wallet identity. Always persist it in a secure secrets manager (AWS Secrets Manager, HashiCorp Vault, GCP Secret Manager, etc.).
First run — let the SDK generate the key, then save it:
const session = await client.authenticate({
userIdentity: 'merchant-backend-user-001',
});
// Persist this immediately
await secretsManager.set('SERVER_WALLET_ACCESS_KEY', session.accessKey);
Subsequent runs — provide the saved key:
const session = await client.authenticate({
userIdentity: 'merchant-backend-user-001',
accessKey: process.env.SERVER_WALLET_ACCESS_KEY,
});
Automatic Token Refresh
Authenticated API calls automatically handle expired tokens:
- A call receives a
401 Unauthorized response
- The SDK sends
POST /auth/refresh with session credentials
- If the refresh succeeds, the access token is updated and the original call is retried
- If the refresh fails, the error is thrown to the caller
No configuration is needed — this behavior is built into every authenticated method (whoami, signTransaction, exportPrivateKey, etc.).
Identity Conflicts
If you call authenticate with a userIdentity that already exists but provide a different accessKey, the backend returns a 409 CONFLICT error:
ConflictError: userIdentity 'merchant-backend-user-001'
already exists with a different access key
This protects against accidental identity collisions. To resolve:
- Use the original access key for this identity, or
- Choose a different
userIdentity string
Next Steps