# Device flow (/docs/auth/flows/device)



The device flow is intended for clients that cannot conveniently host an
interactive browser login, such as constrained-input devices and some CLI tools.
The user authorizes the application in a separate browser while the client polls
for completion.

<SalesforceReference title="OAuth 2.0 Device Flow for IoT Integration" href="https://help.salesforce.com/s/articleView?id=xcloud.remoteaccess_oauth_device_flow_ca.htm&language=en_US&type=5" />

## Request a device code [#request-a-device-code]

```ts
import { SalesforceAuth } from "@kysoql/auth";

export function beginDeviceAuthorization() {
  const auth = new SalesforceAuth({
    loginUrl: "https://login.salesforce.com",
    clientId: "external-client-app-id",
  });

  return auth.requestDeviceAuthorization({
    scope: ["api"],
    redirectUri: "http://127.0.0.1:1717/callback",
  });
}
```

The response contains the device code, user code, verification URI, polling
interval, and any expiry returned by Salesforce. Display the verification URI
and user code to the user.

## Poll once [#poll-once]

```ts
import { SalesforceAuth, SalesforceOAuthError } from "@kysoql/auth";

const auth = new SalesforceAuth({
  loginUrl: "https://login.salesforce.com",
  clientId: "external-client-app-id",
});

export async function pollOnce(deviceCode: string) {
  try {
    return await auth.pollDeviceAuthorization({ deviceCode });
  } catch (error: unknown) {
    if (
      error instanceof SalesforceOAuthError &&
      (error.code === "authorization_pending" || error.code === "slow_down")
    ) {
      return undefined;
    }
    throw error;
  }
}
```

`auth.pollDeviceAuthorization()` performs one poll only. The application owns the
schedule and must respect Salesforce's returned interval and `slow_down`
responses.

<SalesforceReference title="Configure an OAuth 2.0 Device Flow for External Client Apps" href="https://help.salesforce.com/s/articleView?id=sf.meta_configure_device_flow_external_client_apps.htm&language=en_US&type=5" />
