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

# QR code verification

> Use the Web SDK to generate QR code challenges which can be scanned and authenticated using a mobile app.

<Info>
  Check out our end-to-end guide on [how to implement QR code verification using
  Authsignal](/authentication-methods/app-verification/qr-code).
</Info>

## Start a QR code challenge

```js theme={null}
const { data } = await authsignal.qrCode.challenge({
  action: "kiosk-login",
  onStateChange: (state: ChallengeState, token?: string) => {
    if (state === "approved" && token) {
      // Validate the challenge on your backend
    }
  },
});
```

### Parameters

<ResponseField name="action" type="string" required>
  The action being performed.
</ResponseField>

<ResponseField name="onStateChange" type="function" required>
  A function that is called when the challenge state changes.

  <Expandable title="parameters">
    <ResponseField name="state" type="string">
      The current state of the challenge.

      Possible values are: `unclaimed`, `claimed`, `approved`, `rejected`.
    </ResponseField>

    <ResponseField name="token" type="string">
      A token which can be used for [server-side
      validation](/sdks/server/challenges#validate-challenge).
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="onRefresh" type="function">
  A function that is called when the challenge should be refreshed.

  <Expandable title="parameters">
    <ResponseField name="challengeId" type="string">
      The ID of the Authsignal challenge. The value of this should be rendered as a QR code.
    </ResponseField>

    <ResponseField name="expiresAt" type="number">
      The timestamp in ISO 8601 format at which the challenge will expire.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="custom" type="object">
  A JSON object which can include any key/value pairs. Can be used to provide additional context to the challenge which can be reviewed on the user's mobile device.
</ResponseField>

<ResponseField name="refreshInterval" type="number">
  The interval in milliseconds at which the challenge should be refreshed. Defaults to `540000` (9 minutes). This should be set to a value lower than your token's expiry time to allow a tolerance for the challenge to be completed.
</ResponseField>

<ResponseField name="polling" type="boolean">
  Whether to poll for the challenge result using RESTful API endpoints. Should only be used if you are unable to use WebSocket connections.

  Defaults to `false` and uses WebSockets.
</ResponseField>

<ResponseField name="pollInterval" type="number">
  The interval in milliseconds at which the challenge should be polled. Defaults to `5000` (5 seconds).

  Only relevant when `polling` is set to `true`.
</ResponseField>

### Response

<ResponseField name="response" type="AuthsignalResponse<QrCodeChallengeResponse>">
  <Expandable title="properties">
    <ResponseField name="data" type="QrCodeChallengeResponse">
      <Expandable title="properties">
        <ResponseField name="challengeId" type="string">
          The ID of the Authsignal challenge. The value of this should be rendered as a QR code.
        </ResponseField>

        <ResponseField name="expiresAt" type="number">
          The timestamp in ISO 8601 format at which the challenge will expire.
        </ResponseField>

        <ResponseField name="deviceCode" type="string">
          A short code which can be entered manually on the user's mobile device as a fallback to scanning the QR code. Only available when `polling` is set to `true`.
        </ResponseField>
      </Expandable>
    </ResponseField>

    <ResponseField name="errorCode" type="string">
      See the [Error handling](/sdks/client/web/error-handling) section for more details.
    </ResponseField>

    <ResponseField name="errorDescription" type="string" />
  </Expandable>
</ResponseField>

## Refresh a QR code challenge

```js theme={null}
await authsignal.qrCode.refresh();
```

This can only be called after a QR code challenge has been initiated. The callback functions passed to the `challenge` method will be re-used.

### Parameters

<ResponseField name="custom" type="object">
  A JSON object which can include any key/value pairs. Can be used to update context to the
  challenge which can be reviewed on the user's mobile device.
</ResponseField>

## Disconnect a QR code challenge

Call `disconnect` to tear down the active challenge. This closes the WebSocket connection (or stops polling) and clears any refresh timers. Call it when the QR code is no longer displayed, for example when the user navigates away.

```js theme={null}
authsignal.qrCode.disconnect();
```
