authentication config with authType: "user_credentials" on the tool. IMP renders a secure credential form directly in the chat UI the first time the tool is called, stores the values encrypted at rest, and injects them into every subsequent execute call. Your code never receives an unentered form; it only runs when credentials are present.
Prerequisites
- Completed Custom tools — you know how to build an
ExuluTool. - Read ExuluTool — configuration — the user credentials section explains
ExuluUserCredentialsConfigandCredentialField.
What IMP handles for you
Whenauthentication is declared with authType: "user_credentials":
- Credential form prompt — On the first call (and whenever stored credentials have been revoked or invalidated), IMP skips
executeand returns a structuredcredentialRequestpayload. The chat interface renders this as a typed form card — password fields are masked,helptext is shown below each input. - Secure submission — When the user submits the form, the frontend posts
{ nonce, values }toPOST /credentials/submit. The endpoint requires a valid session and cross-checks the session user against the nonce (15-minute TTL, AES-encrypted) to prevent replay attacks across users. - Encrypted storage — Values are AES-encrypted (keyed off
NEXTAUTH_SECRET) and stored in theuser_credentialstable under(provider, userId). Plaintext never persists on disk. - Injection — On every subsequent tool call, IMP decrypts the stored row and injects
credentialsintoinputsbefore callingexecute. Values transit the server only — they never reach the model. - History scrubbing — The
credentialRequestpayload (which contains the nonce) is replaced in the model-visible conversation history with a scrub placeholder. A system guardrail also instructs the model to never ask the user to type credentials into the chat.
inputs.credentials in execute.
What you will build
An ERP integration tool that authenticates with an API key. The key is collected once through a secure in-chat form and reused for every subsequent call.1
Declare the tool with user credentials authentication
src/tools/erp-orders.ts
credentials object injected into inputs is typed as Record<string, string> — the same shape the user submitted through the form, one key per fields[].name:2
Understand the credential form flow
When the agent calls
erp_orders for a user who has not yet entered credentials:- IMP checks the credential store for a
(example_erp, userId)row. None exists. - IMP skips
executeand returns a structured short-circuit result:
- The chat interface renders a credential form card. Password fields are masked; help text appears below each input.
- The user enters their API key and username and clicks Save. The frontend posts
{ nonce, values }toPOST /credentials/submitusing the current session cookie. - The submit endpoint verifies the session, decrypts the nonce (rejects if expired or tampered), cross-checks the session user against the nonce’s
userId, runs the optionalvalidatehook, then writes the AES-encrypted values to the store. Returns{ ok: true }. - The agent is notified that the form was submitted and calls
erp_ordersagain. - IMP finds the stored row, decrypts it, and injects
credentialsintoexecute.
3
Share credentials across tools
Multiple tools that access the same provider (for example, an
erp_invoices tool alongside erp_orders) should share the same provider key. The user fills in the form once; all tools in the group reuse the same stored row.src/tools/erp-invoices.ts
4
Self-healing with CredentialInvalidError
If the upstream API rejects the stored key (for example, the user rotated their API key in the ERP console), throw
CredentialInvalidError inside execute. IMP catches it, deletes the stale stored row, and returns a fresh credential form in the same turn — no extra code required.CredentialInvalidError takes two arguments: the provider string (must match authentication.provider) and an optional human-readable reason. The reason is included in the error message but is not shown directly to the user.Only throw CredentialInvalidError for the tool’s own provider. Any other error is re-thrown and surfaces as a normal tool error.5
Register on the app
src/exulu.ts
NEXTAUTH_SECRET (already set for your IMP installation) is used as the encryption key. Make sure BACKEND is set to the backend’s public base URL so IMP can build the submitUrl in the credential form.Security posture
User management
Users can view and revoke their saved credentials in Settings → Connections. The interface lists every(provider, authType) pair the user has stored, with a Revoke button for each. After revocation, the next tool call that needs those credentials shows the credential form again.
The same operations are available via the API (session-authenticated):
What you built
- An ERP orders tool with
ExuluUserCredentialsConfigthat collects an API key and username through a secure in-chat form. - A
validatehook that tests the credentials against the upstream API before storing them. - A
CredentialInvalidErrorthrow that triggers automatic re-prompting when the stored key is rejected. - A shared
providerkey so multiple ERP tools reuse the same credential set.
Next steps
ExuluTool — configuration
Full ExuluUserCredentialsConfig reference — every field, CredentialField type, and the injected credentials shape.
OAuth tools
Use the authorization-code + PKCE flow when the provider supports OAuth instead of static keys.
Custom tools
Build tools without authentication using Zod schemas and admin config params.
Tool approvals
How users see and approve tool calls in the chat interface.