Skip to content

Sign in in a native app

Target Audience: Developers, Stakeholders

Introduced in Payway 4.10.

For native iOS / Android apps, your app runs the provider sign-in itself (with the platform's Google / Microsoft / Apple SDK) and posts the resulting id_token to Payway. Payway validates it and turns it into an SSO2 session — you never handle provider secrets, and there is no browser redirect or web-view cookie to manage.

This is the same trust model as the web flow, just with a different party running the provider handshake: the identity is only ever accepted because it is carried in the provider-signed id_token, which Payway validates against the provider's JWKS. See the overview for the account model (:resolved / :new / :link_required).

Prerequisites

  • Your app authenticates to Payway exactly like Support for native apps — a client-auth JWT (t) signed with your org's API client secret (cid / iss / aud=pw-sso). That token authorises transport; the provider id_token is the separate identity proof.
  • Register your app's native OAuth client with the provider (Google / Microsoft / Apple). Send its client id to Adeprimo — it is added to the org's native audiences so Payway accepts an id_token whose aud is that native client. (Provider config + secrets stay with Adeprimo.)

Flow

  1. Request a nonce from Payway (replay protection).
  2. Run the provider sign-in in your app, including the nonce in the request, and obtain the provider id_token.
  3. Sign in — post the id_token + nonce to Payway; it validates and reports the outcome.
  4. On :new, collect terms + profile and create the account, then sign in again to get the session.

1. Nonce

POST {sso}/social/{provider}/native/nonce with your client-auth JWT. Single-use, short-lived; Payway burns it when the resulting id_token is presented.

curl -X POST https://sso.worldoftulo.com/social/google/native/nonce \
  -H 'Content-Type: application/json' -d '{ "t": "<client-auth JWT>" }'
Response: { "nonce": "<single-use nonce>" }. Include this nonce in your provider sign-in request.

2. Provider sign-in (your app)

Run the platform sign-in SDK for the provider, passing the nonce. You get back a provider id_token. This step is entirely in your app; Payway isn't involved.

3. Sign in

POST {sso}/social/{provider}/native/login:

curl -X POST https://sso.worldoftulo.com/social/google/native/login \
  -H 'Content-Type: application/json' \
  -d '{ "t": "<client-auth JWT>", "id_token": "<provider id_token>", "nonce": "<nonce from step 1>" }'

Payway burns the nonce, validates the id_token (JWKS signature, issuer, aud ∈ your org's web client id ∪ native audiences, and the nonce), maps the identity to an account, and returns one of:

status Body What you do
resolved SSO2 session token (sid / aid / at) exchange at for the user's access token (ticket exchange) — signed in
link_required { status, email } an account with that email exists but isn't linked — sign the user in normally, then connect the provider
new { status, signup_token, email } no account yet — go to step 4

The :resolved body is the same session-token shape as Create session, delivered in the JSON body.

4. Create the account (:new)

Collect terms acceptance + any profile fields, then call the Payway API:

POST {payway-api}/external/social/create (OAuth access token, scope /external/social/native/w):

{ "signup_token": "<from step 3>", "terms_accepted": true, "first_name": "…", "last_name": "…" }

Payway redeems the single-use signup_token (the identity is taken from it — never from these params), creates the account, and returns { "account_id": "…" }. Terms are your responsibilityterms_accepted is required and the account is not created without it.

The account now exists and is linked, so sign in again (step 3) — it now returns :resolved and you get the session. (Native create does not itself return a session.)

Per-provider note on account identity

A user is matched to an account by the provider's stable user id (sub). Google issues the same sub across your web and native OAuth clients, so a user who signed up on the web resolves to the same account natively. Microsoft and Apple issue a per-client sub, so the native client's sub differs from the web one for the same person — that user resolves as :new natively even if they exist on the web. Plan for that if you offer both web and native sign-in.

See also