How it works
- Your server creates a session token via
POST /v2/token - Your frontend mounts
<DeckAuthComponent />with the token and all configuration - The component renders a secure UI (hosted at
auth.components.deck.co) where the user selects a source and enters credentials - Credentials go from the component directly to the Deck API and into the Credential Vault. They never touch your page
- On success, the component returns the new Credential ID via
onSuccess
Restrictions
- Collects credentials via
username_password(default) orsource_fields(opt in per source throughsourceConfig). No other auth method is supported. - Does not support chaining to tasks with inputs
Installation
Quick example
Create a session token on your server:Client
Session token
Every auth component session starts with a server-side token. The token is authentication only. It proves the request came from your backend. All configuration (sourceId, appearance, etc.) is passed on the component, not the token.POST /v2/token
Creates a session token for the Auth Component.
Authentication: Authorization: Bearer sk_live_...
Request body: None
Response (201):
Token lifecycle
- Tokens expire 30 minutes after creation
- Expired tokens return a clear error to
onError
Component props
The component does not own its lifecycle. Your app does. When
onClose fires, you decide what happens (unmount, navigate, show a confirmation, etc.).
Callbacks
onSuccess
onCancel
onClose.
onError
type is the error category. code is the machine-readable identifier. message is human-readable and may change. Switch on type and code, not message. See Error handling for all error codes.
onClose
onClose fires when the user dismisses the flow — via the persistent close (X) icon, the Escape key, or a Cancel/Close button on the canceled or error screen. You handle the teardown.
By default the X is shown whenever onClose is provided and hidden when it is omitted. To control the two independently — for example, to embed the component in your own modal that already has a close control — pass showCloseButton:
onClose entirely hides the X and leaves the Cancel/Close buttons with no handler, so prefer showCloseButton={false} when you still want those buttons to work.
If a task run is in progress when the user closes the component, the task run continues running in the background. To cancel it, use the cancel endpoint from your onClose handler.
showCloseButton
onClose. Defaults to onClose != null, so existing integrations are unaffected. Pass onClose together with showCloseButton={false} to hide the X while keeping the Cancel/Close buttons (which share the same close handler) functional.
Source selection
ThesourceId prop controls what the user sees before credential capture.
Source fields
Some sources need values beyond username/password: an account number, a company ID, etc. ThesourceConfig prop attaches source fields to a source’s credential form, keyed by source ID (or "*" as a default for any source without its own entry). By default these fields are collected alongside username/password, but a source can also authenticate on source fields alone (see Auth method). Collected values are stored on the credential under auth_credentials.source_fields; fields marked tokenized are vaulted.
Only sources that need custom fields get an entry. Every other source renders the standard username/password form.
Entry config
Each entry insourceConfig is keyed by source ID (or "*") and takes:
Auth method
authMethod controls whether the entry’s fields sit alongside username/password or replace them.
A
source_fields entry must declare at least one field; one with none fails fast at mount with source_fields_auth_requires_fields, and an unknown authMethod fails with auth_method_invalid. If the source doesn’t support the selected method, the flow fails at runtime with auth_method_not_supported.
Field config
Every display string (label, placeholder, and each option label) is a LocalizedString: either a plain string, rendered as-is in every locale, or a { "en-US": string; "fr-CA"?: string } map picked by language, falling back to "en-US". The two forms can be mixed within one config.
Behavior
- Scoping is per source: the entry matching the selected source applies, and
"*"covers any source without its own entry. - Stored values are always strings: selects store the option
value, booleans store"true"/"false". Option values and stored values are data and are never localized. - Reconnect (Update Mode) prefills non-tokenized fields from the stored credential and keeps them editable. Tokenized fields render empty (their values are never returned) and are treated as optional even when
required: leave one blank to keep the stored value, or re-enter it to change it, so users aren’t forced to re-enter vaulted values.
Invalid
sourceConfig fails fast: the component fires onError at mount with a source_field_* code rather than erroring at credential creation. See Error handling.Update mode
Pass acredentialId to re-collect credentials for an existing credential instead of creating a new one.
Task linking
Pass ataskId to verify credentials immediately after creation. The component fires a task run using the new credential, and the task run view stays visible while it executes.
Credential status reflects whether the agent could authenticate, not whether the run finished successfully. As long as auth succeeds, the credential becomes
verified even if the run later fails. A failed run does not delete or invalidate the credential. If auth itself fails, the credential becomes invalid.
taskRunView
With taskId present, the task run view is shown while the run executes:
"status": spinner with status text (e.g., “Connecting…”, “Verifying credentials…”)"live": live view of the task run
taskId, no task run view is shown.
Interaction mode
Setmode="interaction" to collect interaction inputs (MFA code, security question, MFA method) from the user during a task run against an existing credentialId or sourceId. The component skips source selection and credential capture, triggers the task run, and renders any pending interaction in place.
Required props
Interaction mode needstaskId plus one of:
Both are validated before the component mounts:
- Omitting
taskIdfiresonErrorwithtask_id_required. - Providing neither a
credentialIdnor a singlesourceIdfiresonErrorwithcredential_or_source_required.
Appearance
Customize the component’s look via theappearance prop.
Theme
Variables
Branding
Upload a logo in the Deck console under Settings → Branding. Deck hosts it and returns a CDN URL on
content.cdn.deck.co. Pass that as logoUrl. Accepted formats are PNG, JPG, JPEG, GIF, and WebP (no SVG). The logo renders into a 40×40 box and is hidden if it fails to load.
For security, the component only loads images from Deck’s content CDN,
data: URIs, and cdn.brandfetch.io. Arbitrary external URLs (for example, https://your-company.com/logo.png) are blocked by its content security policy and will not render.Language
Set the language for all component-rendered copy via thelanguage prop.
language applies to copy the component owns: source picker, credential capture labels and helper text, interaction prompts (generic labels and submit/continue buttons), in-UI error messages, the task run status view (taskRunView: "status"), and the close button and accessibility labels.
Content returned by the source itself (source names, interaction field labels, and other source-defined strings) is not translated by the component and is rendered as the source returns it.
Interactions
Sources may require additional input mid-flow: an MFA code, a security question, an account selection. The component handles these automatically as interactions: a generic pause-and-prompt primitive. When an interaction is required:- The component transitions to an interaction step and renders the fields from the source’s response
- The user fills in the fields and submits
- The source validates. On accept, the flow continues
- Some sources require multiple sequential interactions (e.g., MFA code then a security question)
Error handling
All errors surface throughonError with a uniform { type, code, message } shape. code falls into two groups by where it comes from.
Validation errors
Raised by the component itself before any network request, from checking the token and the prop combination. These are deterministic: a given misconfiguration always produces the same code.Runtime errors
Surfaced by the Deck API and the source as the flow runs. The component forwards the API’stype, code, and message (mapping a couple of generic not-found codes to the specific ones below). Treat this as the set you are most likely to encounter, not an exhaustive list, and handle any unrecognized code as a generic failure.
Error behavior
- Validation errors fire before the iframe mounts. Fix the token or props and remount.
- Token expiry (
token_invalid) terminates the session. Create a new token and remount. - Credential and source errors (
auth_invalid,account_locked, etc.) terminate the session. - Interaction errors (
interaction_timeout) terminate the session. Wrong user input is not an error; the source emits another prompt and the user retries in place.
Embed by URL
For clients that can’t run the React SDK, load the component’s URL in aWebView (for example, in a React Native app) or an <iframe> and pass configuration as query parameters:
URL parameters
Appearance parameter
appearance takes the same AppearanceConfig object as the prop, encoded as a URL-safe JSON string:
theme shorthand instead.
Examples
Configuring via postMessage
URL parameters are subject to URL-length limits, so a largesourceConfig (or any object config you’d rather not URL-encode) is best delivered over postMessage, which has no encoding step and no length limit. The React component uses this same handshake internally.
Load the component with no configuration in the URL (just the bare origin), wait for the READY message, then post an INIT message with the full configuration object:
WebView, run the same window.postMessage({ type: 'INIT', ... }) (via injectJavaScript) once you receive READY through onMessage.
Receiving results
Without React callbacks, the component delivers results as messages to the client:- React Native
WebView: messages arrive viawindow.ReactNativeWebView.postMessageas JSON strings. Read them with theWebView’sonMessagehandler. <iframe>: the same messages arrive viawindow.postMessageto the parent frame.
type and ignore any you don’t handle:
Each message is
{ type, payload }: