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 providerid_tokenis 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_tokenwhoseaudis that native client. (Provider config + secrets stay with Adeprimo.)
Flow¶
- Request a nonce from Payway (replay protection).
- Run the provider sign-in in your app, including the nonce in the request, and obtain the provider
id_token. - Sign in — post the
id_token+ nonce to Payway; it validates and reports the outcome. - 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>" }'
{ "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 responsibility —
terms_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¶
- Sign in overview — the account model and the web flow.
- Connect a provider to an existing account — for signed-in users.
- Support for native apps — the client-auth JWT and session mechanics this builds on.