1. Docs
  2. Authentication
  3. Native & Mobile Apps

Native & Mobile Apps

Signing users in from an installed iOS or Android app, where there is no cookie jar to keep the refresh token in.

What changes on a phone

In a browser, Canopy returns the refresh token as an httpOnly cookie. The browser stores it, sends it automatically, and forbids page scripts from reading it, so a script injected into your site cannot steal it.

An installed app has none of that machinery. There is no cookie jar working in the background, so the token comes back in the response body and your app stores it.

That makes storage your responsibility. Put it in the iOS Keychain or the Android Keystore, the OS-provided secure storage, not in UserDefaults, SharedPreferences, or a file you manage yourself.

Register a native key

Delivery follows the key, not the request. Create a key for the app and mark it native:

In the Developer Console, open Integrations → Publishable Keys for the environment your app signs in to.Choose Create Key, name it after the app (iOS app), and set Used by to Native.Embed the pk_… value in your app and send it as publishable_key on POST /v1/identity/auth/login, exactly as a browser app would.

Sessions created with that key return refresh_token in the JSON body and set no cookie. Nothing else about the call changes.

A publishable key is safe to ship inside an app binary: it names the environment but grants no access on its own. It is not a secret, and it is not an API key.

Delivery is fixed when the session is created

A session records how it delivers its refresh token when it is created, and keeps that for its whole life. A session started by a web key stays on cookies; one started by a native key stays on body delivery, through every rotation.

This is worth understanding rather than working around, because it is what stops a real attack. Publishable keys are public by design: a native key can be extracted from any app binary. If /refresh chose delivery from the key on the request, a script injected into your website could present your native key and be handed the refresh token in the response body. The browser attaches the httpOnly cookie automatically, so the script would never need to read the cookie to spend it.

So there is no parameter for this. /refresh accepts no publishable key at all: it reads the mode off the session. If you need to move a user from one mode to the other, sign them in again.

Rotation on unreliable networks

Refresh tokens are single-use. Every refresh returns a new one and retires the old, and presenting a retired token normally revokes the whole session family: that is the response to theft.

Mobile networks make that awkward. If the response is lost after Canopy has already rotated, your app still holds the old token and will retry with it. Canopy recognises that: a replay is treated as a harmless retry when the token was rotated moments ago and its successor was never used.

An already-used successor means two parties hold tokens from the same chain, which is theft rather than a dropped response, and that does end every session for the identity. Your app does not need to do anything special; just retry the refresh with the token you have.

One environment, one key per app

One environment can hold several keys, and normally does. A web key for your site, a native key for the phone app: same identities, same roles, same hierarchy, just different front doors.

This is the expected arrangement, not a workaround. Keep one key per app so you can retire one without touching the others.

Revoking a native key

Revoking a key stops new sign-ins with it. Sessions already signed in keep working: revoking does not sign anyone out.

Think carefully before revoking a native key. It is baked into a released binary, so anyone who has not updated the app can no longer sign in, and they cannot fix that themselves. Ship the replacement key first, give users time to update, and revoke afterwards.
Environment
API version
v1.0
On this page Was this page helpful?

Tell us how we can improve this guide.