Skip to content
Visor Developers

Meta login and ownership

This page covers the Meta side of setup. It lists the login that gives the phone its tokens, the two receipts that make the phone the owner, and the calls the phone makes to Meta. The trust check that runs on later connections is on Identity and trust.

Setup contacts Meta in two places. First, the user logs in to a Meta account, and the phone exchanges that login for a token. Second, Meta's hardware service issues two receipts that name the phone as owner. After setup, the connection path makes no Meta call. The glasses check the phone's key over the link itself.

The sequence below shows one setup, from the Meta login to the glasses accepting the phone as owner.

sequenceDiagram
    participant Phone
    participant Meta
    participant Glasses
    Phone->>Meta: Authorize page (accounts.meta.com/oidc/)
    Meta-->>Phone: Redirect with code and state
    Phone->>Meta: Token exchange with the code
    Meta-->>Phone: access_token, the FRLA
    Phone->>Meta: AR login with the AR app token and the FRLA
    Meta-->>Phone: ARAe
    Phone->>Glasses: Secure link up
    Phone->>Glasses: Identity request (svc36)
    Glasses-->>Phone: Identity response with device certificate and serial
    Phone->>Glasses: Skip challenge
    Glasses-->>Phone: Skip challenge ack with nonce
    Phone->>Meta: pair_request with certificate, serial, nonce and owner public key
    Meta-->>Phone: Pending receipt and signature
    Phone->>Glasses: Start change owner request with the pending receipt
    Glasses-->>Phone: Start change owner response with the device pending receipt
    Phone->>Meta: pair with the device pending receipt
    Meta-->>Phone: Final receipt and signature
    Phone->>Glasses: Finish change owner request with the final receipt
    Glasses-->>Phone: Finish change owner ack

Meta login

The login runs on Meta's own page and ends at the redirect URI. The phone then exchanges the code for a token.

  1. The phone builds the authorize URL for accounts.meta.com/oidc/. It sends a fixed app id, scope openid, response type code, the redirect URI https://accounts.meta.com/native/oidc/redirect/metaai and a state of 16 random bytes, base64url without padding.
  2. The user signs in on Meta's page.
  3. The login ends at the redirect URI. The phone reads code and state from that URL. The redirect page is not loaded, and the phone does not read the page content.
  4. The phone rejects a redirect whose state differs from the one it sent. A redirect without a code fails.
  5. The phone posts the code to api.accounts.meta.com/native/oidc/token-exchange/ with the fields mt_app_id, oidc_auth_code and redirect_uri. The response must hold access_token and user_id. A 500 answer means the code belongs to another flow.
  6. The access_token from step 5 is the FRLA.

Token kinds

The phone uses five credentials. The table gives their names, sources and uses.

Name Source Used for
FRLA access_token of the token exchange Field frl_access_token on the AR login
ARAe access_token of the AR login Field user_access_token on the hardware calls, with user_token_universe set to ar
AR app token A fixed app token, shown here as <AR app token> Field access_token on the AR login
HW app token A fixed app token, shown here as <HW app token> Field access_token on the hardware calls
FRL app token A fixed app token, shown here as <FRL app token> The Authorization: OAuth header on the native login queries to meta.graph.meta.com/graphql

The three app tokens are the Meta AI app's own client tokens, and Visor does not ship them. To build Visor from source, extract them from the official Meta AI app. They are the strings that start with HW|, AR| and FRL|. They go in local.properties as VISOR_META_HW_TOKEN, VISOR_META_AR_TOKEN and VISOR_META_FRL_TOKEN (see the README).

The AR login is ar.graph.meta.com/login. The phone sends the AR app token and the FRLA. It also sends two new random UUIDs as logging_session_id and device_id, format set to json, and the flags generate_session_cookies and generate_analytics_claim set to 1. The response access_token is the ARAe. A response with an error field is a failure, and its message gives the cause.

Each AR login opens a new Meta session and ends the older ones. A request that still carries an older ARAe then fails with OAuth error 190, "The session has been invalidated". So the phone runs the AR login once and uses that ARAe for every call, and logs in again only after a 190. A FRLA that Meta refuses fails the AR login.

Ownership receipt and change owner

Each pair of glasses holds one owner key, an EC P-256 key. Change owner replaces that key with the phone's key. Meta's hardware service issues two receipts for the change. Each receipt is Meta's signature over a JSON body. The glasses take the receipts over the identity service, svc36. The phone calls the hardware host graph.facebook-hardware.com.

On the link, a receipt is a message with field 1 for the signature and field 2 for the JSON body.

The change-owner flow runs in this order. The phone opens one channel on svc36 and sends its messages on it. Only the first message on a channel carries the service id and the message type. Later messages report service id 0.

Step Type (decimal, hex) Direction Body
Identity request 12288 (0x3000) Phone to glasses Empty
Identity response 12289 (0x3001) Glasses to phone Field 1 device certificate (DER), field 2 serial as ASCII text
Skip challenge 8192 (0x2000) Phone to glasses Empty
Skip challenge ack 8193 (0x2001) Glasses to phone Field 1 nonce, 16 bytes
Start change owner request 8194 (0x2002) Phone to glasses Pending receipt from Meta
Start change owner response 8195 (0x2003) Glasses to phone Device pending receipt: field 1 signature, field 2 JSON with the certificate
Finish change owner request 8196 (0x2004) Phone to glasses Final receipt from Meta
Finish change owner response 8197 (0x2005) Glasses to phone Empty acknowledgement

The hardware calls run between those messages:

  1. pair_request is a form POST to graph.facebook-hardware.com/pair_request, gzip compressed. Its fields are access_token (HW app token), user_access_token (ARAe), user_token_universe (ar), pair_protocol_version (4), device_cert (base64 of the device certificate), serial_number and additional_data. The last is JSON text with device_nonce (base64 of the nonce from the skip challenge), app_pubkey (base64 of the phone's 64-byte public key) and secondary_cert. secondary_cert is empty for glasses. For the Neural Band it is base64 of field 5 of the identity response, and without it pair answers HTTP 500.
  2. The response holds pending_ownership_receipt and receipt_signature (base64). When the receipt body is an object, the phone writes it back as JSON the way Python's json.dumps does, so the bytes match the reference client.
  3. The phone sends the pending receipt to the glasses in step 8194.
  4. The glasses answer with a device pending receipt in step 8195.
  5. pair is a form POST to the same host. It sends device_pending_ownership_receipt (the JSON text), device_pending_ownership_receipt_signature (base64) and the common fields. The field ephemeral_pairing_flag is left out for a normal pairing.
  6. The response holds final_ownership_receipt and its signature. The phone sends the final receipt to the glasses in step 8196.
  7. The glasses acknowledge in step 8197. The phone reads serial and user_id from the final receipt body.

An HTTP status of 400 or more fails the step. A body with an error field fails with its message. An error on the channel comes as a status frame, and it fails the step that waits for a reply.

Lookups by serial

The phone asks Meta for what the glasses do not report about themselves. Each lookup is a form-encoded GraphQL request to ar-genai.graph.meta.com/graphql with the ARAe, like the update query on Firmware.

Operation Variables Answer
WearableDeviceSKUBySerialNumber serial_number frame_style_new, frame_color_new, lens_color_new (each a lowercase code and a display name) and device_size. A locale variable translates the names
WearableDeviceAssetsBySerialNumbers serial_numbers, a list Pictures of the pair: per serial, sku_specific and device_specific assets with a light and a dark PNG URL. The SKU picture shows the real frame and lens. Category 2 is the device picture
WearableDeviceAssetsForPrePairing none Light and dark pictures of every model and SKU, for a list of pairs before setup
FetchConstellationUpdates, FetchConstellationFeatureUpdates serial, device type, firmware version, feature Firmware images and resource packs. See Firmware

The serial is the svc100 serial. For the SKU lookup, the bundle serial from svc22 comes first when the glasses report one. Each request also needs the operation's document id, which the official app sends as client_doc_id.

What Meta sees and when

Meta sees the account login, the glasses' certificate and serial number, and the phone's owner public key. The phone sends no user name and no phone serial.

When Host and call What the phone sends
Login, once per sign-in accounts.meta.com/oidc/, then api.accounts.meta.com/native/oidc/token-exchange/ The typed login on Meta's page, the fixed app id, the state, the code, the redirect URI and a fixed user agent that names the Meta AI Android app
Once per run, and after an OAuth 190 ar.graph.meta.com/login The AR app token, the FRLA, two new random UUIDs and the session and analytics flags
Lookups ar-genai.graph.meta.com/graphql The ARAe and the serial number, or no serial for the pre-pairing pictures
Setup, at the pair request graph.facebook-hardware.com/pair_request The device certificate, the serial number, the device nonce, the owner public key and the ARAe
Setup, at the pair graph.facebook-hardware.com/pair The device pending receipt and its signature
After setup None on the connection path Nothing. The connection path makes no Meta call

What Meta keeps, and for how long, is not known.

Reference code: WebLogin.kt, Frla.kt, Provision.kt, ProvisionSession.kt

Open questions

  • Unknown: whether the glasses verify the receipt signatures. The glasses' check of the final receipt is not visible on the link. The phone reads only the acknowledgement and the status frames.
  • The lifetime of a FRLA is not known. A refusal from Meta is the only sign that a login has expired.
  • Unknown: whether any call needs the universe value fb. Setup uses only ar.