Skip to main content
The Auth Component is a pre-built React component that collects end-user credentials, stores them in the Credential Vault, and creates a Credential. Credentials never touch your systems. It handles source selection, username/password capture, interactions (MFA, security questions), and error states out of the box.
Want full customization and control over the UX? See Building your auth flow to build your own using the API directly.

How it works

  1. Your server creates a session token via POST /v2/token
  2. Your frontend mounts <DeckAuthComponent /> with the token and all configuration
  3. The component renders a secure UI (hosted at auth.components.deck.co) where the user selects a source and enters credentials
  4. Credentials go from the component directly to the Deck API and into the Credential Vault. They never touch your page
  5. On success, the component returns the new Credential ID via onSuccess

Restrictions

  • Collects credentials via username_password (default) or source_fields (opt in per source through sourceConfig). No other auth method is supported.
  • Does not support chaining to tasks with inputs

Installation

React 18+ is a peer dependency.

Quick example

Create a session token on your server:
Mount the component in your React app:
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

Fires when a verification task run is canceled out-of-band (for example, you call the cancel endpoint while the run is in progress). This is not user dismissal of the component, which is 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:
Omitting 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

Controls whether the persistent close (X) icon is rendered, independently of 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

The sourceId 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. The sourceConfig 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.
Each field is either a config object (presented to the user) or a plain string (a silent pass-through: stored on the credential, never shown).

Entry config

Each entry in sourceConfig 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 a credentialId to re-collect credentials for an existing credential instead of creating a new one.

Task linking

Pass a taskId 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.
Do not rely on onSuccess with verified: false to detect a failed verification. When the run fails with an error (including an authentication failure, auth_invalid), the component fires onError, not onSuccess. onSuccess with verified: false only occurs for a run that failed without returning an error. Handle verification failures in both onError and the verified field of onSuccess.
The task you pass as taskId must actually authenticate with the source. A task that only visits a public page will not challenge the credential, and running it will not move the credential from unverified to verified. Pick (or create) a task whose first step is logging in.

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
Without taskId, no task run view is shown.

Interaction mode

Set mode="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 needs taskId plus one of: Both are validated before the component mounts:
  • Omitting taskId fires onError with task_id_required.
  • Providing neither a credentialId nor a single sourceId fires onError with credential_or_source_required.

Appearance

Customize the component’s look via the appearance 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 the language 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:
  1. The component transitions to an interaction step and renders the fields from the source’s response
  2. The user fills in the fields and submits
  3. The source validates. On accept, the flow continues
  4. Some sources require multiple sequential interactions (e.g., MFA code then a security question)
The component does not enforce its own interaction timeout. Timeout windows are set by the source and handled by the backend. The user cannot go back to credential entry from an interaction step (credentials have already been created). See Interactions for more on how Deck models interactions.

Error handling

All errors surface through onError 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’s type, 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 a WebView (for example, in a React Native app) or an <iframe> and pass configuration as query parameters:
Each parameter does what its prop does, and the flow is otherwise the same as the React component.

URL parameters

Appearance parameter

appearance takes the same AppearanceConfig object as the prop, encoded as a URL-safe JSON string:
Malformed JSON is ignored and theming falls back to the default. For a theme-only change, use the theme shorthand instead.

Examples

Configuring via postMessage

URL parameters are subject to URL-length limits, so a large sourceConfig (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:
In a React Native WebView, run the same window.postMessage({ type: 'INIT', ... }) (via injectJavaScript) once you receive READY through onMessage.
Pick one channel. Don’t put a token in the URL if you’re going to postMessage: the component self-initializes from the URL first, and the two configurations would conflict. Configure via URL parameters or via postMessage, not both.

Receiving results

Without React callbacks, the component delivers results as messages to the client:
  • React Native WebView: messages arrive via window.ReactNativeWebView.postMessage as JSON strings. Read them with the WebView’s onMessage handler.
  • <iframe>: the same messages arrive via window.postMessage to the parent frame.
Every message the component emits is forwarded, not only the terminal results. Switch on type and ignore any you don’t handle: Each message is { type, payload }: