Develop
Develop
Select your platform

Login API

Updated: Apr 6, 2026
Logging into third-party apps in-headset can be high-friction when users must type credentials or manually enter short-lived device codes on another device. This guide is intended for developers who use (or want to use) the OAuth 2.0 Device Authorization Grant (device code) flow to log users into their app within the Quest headset.
With a typical OAuth Device Authorization Grant flow, the headset displays a short-lived code that the user must recall and then enter in a browser on a separate device. On Quest, this is especially error-prone because the code is shown inside the headset, making it harder for the user to remember accurately while switching to another screen.
Meta Horizon OS provides the send_auth_url login API to reduce this friction. With send_auth_url, your app can send a partner-owned authentication URL (based on its existing device-code or token issuance flow) to the user’s Meta Horizon mobile app. Meta Horizon OS forwards the URL to the user’s phone with the short-lived code pre-populated, so the user can complete authentication and consent on mobile without manually retyping or remembering the code. Your app then finalizes login on the headset using its existing device-code or token issuance flow.
This is especially useful if you already support Device Code login flows on TV or other constrained-input platforms.

When to use this API

Use send_auth_url when:
  • Your login flow can be completed through a URL on mobile (browser or native app)
  • You already support (or can implement) an OAuth 2.0 Device Authorization Grant flow, where the headset can log in after the user approves the login on a secondary device

User experience

  1. The user opens your app on their Quest headset and selects Sign in.
  2. Your app requests a short-lived verification URL from your server (typically containing an embedded device code).
  3. Your app calls the send_auth_url(auth_url) API.
  4. Horizon OS shows a confirmation dialog asking the user to allow sending the link to their mobile device.
  5. If approved, the user receives a notification in the Meta Horizon mobile app. Tapping it opens your authentication URL in a browser or your app.
  6. The user signs in and approves the login on the Quest headset.
  7. On the headset, your app polls until it can exchange the device code for tokens to complete login.

API details

SDK and libraries

This API requires the following Platform SDK packages:
For instructions on adding these packages to your project, see the Kotlin development guide.

Provider

The API uses the logged-in Quest OS user context to deliver the partner-owned authentication URL to that user in the Meta Horizon mobile app through an OS-driven notification. If the user is signed into multiple mobile devices, the notification may be delivered to any eligible device.

Description

send_auth_url allows apps to initiate a login flow using the Meta Horizon mobile app. The provided auth_url is delivered to the user’s Horizon mobile app and opened when the user taps the notification. This is the verification_uri per the OAuth 2.0 Device Authorization Grant.

Authentication

This API uses the Quest OS user session for backend calls. Your app doesn’t need to manage Meta credentials for this operation.

Parameters

ParameterTypeDescription
auth_url
string
Your verification_uri (HTTPS URL) that, when opened on mobile, lets the user authenticate and approve the headset login. In an OAuth 2.0 Device Authorization Grant (RFC 8628) flow, this typically corresponds to your verification_uri or verification_uri_complete and includes the short-lived user_code (for pre-population on mobile). Example pattern: https://amazon.com/code?user_code=...&client=QuestAPI

Return value

Intent-based (Android): the SDK returns an Intent that must be launched (for example, through ActivityResultLauncher) to show the confirmation dialog and complete delivery of auth_url to mobile.

Example integration (Kotlin)

import com.meta.horizon.platform.sdk.users.Users
import kotlinx.coroutines.launch

// Somewhere in your login UI handler
onLoginWithHorizon = {
  coroutineScope.launch {
    val users = Users()

    // Example only (do NOT hardcode in production):
    // https://partner.example.com/device?code=ABC123
    //
    // The user_code is effectively a nonce and must be generated server-side
    // per login attempt (RFC 8628 S3.2).
    val authUrl = getAuthUrlWithUserCode()

    val intent = users.send_auth_url(authUrl)

    activityLauncher?.launch(intent)
      ?: error("Activity launcher not initialized")
  }
}

/**
 * 3P-defined helper that fetches a freshly-generated device/user code from the 3P backend
 * and returns the full verification URL to show to the user.
 *
 * RFC 8628 S3.2: https://datatracker.ietf.org/doc/html/rfc8628#section-3.2
 */
suspend fun getAuthUrlWithUserCode(): String {
  val response: DeviceCodeResponse = fetchDeviceCodeFrom3PBackend()
  return "${response.verification_uri}?code=${response.user_code}"
}

// Example response shape (align to whatever your backend returns).
data class DeviceCodeResponse(
  val verification_uri: String,
  val user_code: String,
)

/**
 * Replace this with your real network call to your 3P backend service.
 * This is intentionally not implemented in the sample.
 */
suspend fun fetchDeviceCodeFrom3PBackend(): DeviceCodeResponse {
  TODO("Call your 3P backend to generate user_code/device_code and return verification_uri + user_code")
}
Adapt the example for your app. Make sure the URL is generated per-login attempt and expires appropriately.

Error handling

Handle and surface appropriate UX for these cases:
ErrorMeaningRecommended UX
OK
Request sent successfully
Continue login flow; show “Check your phone”
USER_CANCELLED
User declined in confirmation dialog
Keep user on login screen; allow retry
NETWORK_ERROR
Transient network failure
Show a network error with a retry option
FORBIDDEN
Server denied request
Show user-facing error and fallback options
INVALID_URL (2005)
URL is malformed or invalid
Log error; regenerate URL; ensure HTTPS
TOO_MANY_REQUESTS
Throttled
Back off and retry; avoid spamming the API

Security and privacy guidance

  • Use short-lived user_code and device_code values.
  • Don’t include sensitive user data in auth_url query parameters.
  • You can measure success by tracking whether a token is issued for the corresponding device code.
  • Device-code flows can inherently enable linking devices to accounts. Make sure your use complies with your policies and any applicable review requirements.

Minimum OS version requirement

To make sure your app only runs on devices that support the Login API, declare a minimum Horizon OS SDK version in your app manifest. This lets the platform gate installation and launch on older OS versions and prevents runtime failures when the API is unavailable. Add the uses-horizonos-sdk stanza and set horizonos:minSdkVersion (and typically horizonos:targetSdkVersion) to the minimum version that includes the login capability. For example:
<manifest xmlns:horizonos="http://schemas.horizonos/sdk">
  <horizonos:uses-horizonos-sdk
      horizonos:minSdkVersion="83"
      horizonos:targetSdkVersion="83" />
  ...
</manifest>
This approach is recommended over relying solely on runtime checks because it provides clearer compatibility guarantees and a better user experience by avoiding unsupported flows on older headsets. For more details, see Minimum OS versions.
If the API is unavailable (older OS version or unsupported device), fall back to your standard device-code flow where users manually enter the URL and code on another device.