In an Expo app, what does expo-auth-session's makeRedirectUri return in a development build versus Expo Go, and why does that matter for OAuth?
answer
- the redirect must match the registration
- development build: scheme://path
- Expo Go: exp://host:8081/--/path
- native option wins in standalone and bare
- the auth.expo.io proxy is gone
basics
~20 sIn a development or production build makeRedirectUri returns your scheme URL, such as expenses://auth; in Expo Go it returns an exp:// URL tied to the dev server's address. Identity providers need a fixed, registered redirect, so OAuth is developed in a development build.
solid answer
~40 s`makeRedirectUri({ scheme, path })` builds the URL the identity provider sends the user back to, via `expo-linking`. In a development or production build it uses your app config `scheme` (or the `scheme` option), giving `expenses://auth`. In **Expo Go** it produces something like `exp://192.168.1.20:8081/--/auth`, which changes with the development machine's address and is not your app's scheme, so it cannot be registered sensibly; Expo's guide says Expo Go cannot be used to develop OAuth for that reason. In standalone and bare builds the `native` option, when given, takes precedence over everything else. Whatever it returns must match the redirect registered with the provider and the one passed to the token exchange. The old `auth.expo.io` proxy (`useProxy`) has been removed.
code
typescript · 6 linesimport { makeRedirectUri } from 'expo-auth-session';
// Computed once and reused for the auth request and the token exchange.
export const redirectUri = makeRedirectUri({ scheme: 'expenses', path: 'auth' });
// development or production build: expenses://auth
// Expo Go: exp://<dev-server-ip>:8081/--/authgo deeper
Remember that the redirect must match what the provider has registered, and that OAuth is tested in a development build.
Explain what makeRedirectUri returns per environment, which options change it, and why the native option wins in standalone builds.
Plan redirect registration across environments and variants, and trace a sign-in that never returns to a mismatched redirect value.
Standardise redirect conventions across several apps and identity providers so registrations stay short, auditable and consistent.
## What a redirect URI is for After the user signs in, the identity provider sends the browser to a **redirect URI** carrying the authorization `code`. Providers only redirect to URIs that were **registered** for the client, and the same URI must be sent again when the code is exchanged. So the value is not cosmetic: a different string in any of those three places breaks sign-in. `makeRedirectUri(options)` in `expo-auth-session` computes that string for the current platform and environment, using `expo-linking` underneath. ## What it returns where | Environment | Example for `makeRedirectUri({ scheme: 'expenses', path: 'auth' })` | Source of the value | |---|---|---| | Development build or production build | `expenses://auth` | the `scheme` option, or the app config `scheme` | | Expo Go | `exp://192.168.1.20:8081/--/auth` | the dev server's address plus the `--` path separator | | Web | a URL on the current page's origin, ending in `/auth` | `window.location`; hard-code it for production web | The options that shape it: - `scheme`: the URL scheme; defaults to the app config's `scheme`. - `path`: appended after the scheme; not added to `native`. - `isTripleSlashed`: `scheme:///path` instead of `scheme://path`; defaults to `false`. - `preferLocalhost`: replaces the dev server's IP address with `localhost`; only useful on the iOS simulator. - `queryParams`: extra query parameters. - `native`: a fixed URI for standalone and bare builds that **takes precedence over all the other options** there. ## Why Expo Go does not suit OAuth Expo Go is a single app shared by every project, so it cannot use your app's custom scheme. Its `exp://` URLs contain the development machine's IP address and port, which change between networks and developers. A corporate identity provider will want a short, fixed list of redirect URIs, and `exp://192.168.1.20:8081/--/auth` is not something you want in it. Expo's authentication guide therefore says to use a **development build** for OAuth work: it carries your scheme and behaves like production. ## How the redirect reaches the app The redirect value is also what each platform uses to recognise the end of sign-in: - **iOS**: `expo-web-browser` hands the redirect's **scheme** to `ASWebAuthenticationSession`, which captures any navigation to that scheme and returns the full URL to the app. An `https` redirect is used only when `preferUniversalLinks` is set and the app has the matching associated domain (iOS 17.4 or later). - **Android**: the provider's redirect opens the app as a deep link, and the library accepts it only if the URL **starts with** the redirect you passed. A registered scheme that the native project does not actually declare means the link goes nowhere and the browser stays open. ## Removed and deprecated - The **`auth.expo.io` proxy** and the `useProxy` option were removed from `expo-auth-session`; a redirect now goes straight to your app. - `getRedirectUrl()` is **deprecated** in favour of `makeRedirectUri()`. ## Practical checklist for an expense app 1. Pick the scheme (for example `expenses`) and make sure the native project actually registers it; that registration is a deep-linking task of its own. 2. Register every redirect the app will send with the identity provider, per environment: for example `expenses://auth` for production and a separate scheme for a staging variant. 3. Compute `redirectUri` once, outside render, and pass the same value to `useAuthRequest` and to `exchangeCodeAsync`. 4. On Android, remember that `expo-web-browser` recognises the return by checking that the incoming URL **starts with** this value, so any difference in scheme or path means the session never reports `success`. 5. Test on a development build, not Expo Go. ## Common mistakes - Registering `scheme://auth` while the app sends `scheme:///auth` because `isTripleSlashed` was switched on in one place only. - Rebuilding the redirect with different options for the token request. - Relying on the Expo Go URL working in production.
- When would you pass the `native` option to `makeRedirectUri`?When a standalone or bare build must use a redirect that cannot be inferred from the app config, for example a provider-mandated URI such as a reversed client ID. In those environments `native` takes precedence over `scheme`, `path` and the rest, so the app sends exactly the registered value.
- Why must the redirect passed to `exchangeCodeAsync` equal the one in the authorization request?The token endpoint compares them, and `expo-auth-session`'s token request requires a `redirectUri` that matches the one used in the auth request. Computing it once and reusing the constant removes the easiest way to get it wrong.
The redirect URI is a return address printed on a prepaid envelope: the identity provider will only post the code to the exact address on file, and Expo Go's address is a shared mailbox whose street number changes whenever you move desks.
saying these in an interview costs you the question
- makeRedirectUri returns the same URL in Expo Go and a build.
- The auth.expo.io proxy is the recommended redirect for native apps.
- Expo Go can use the app's custom scheme for OAuth redirects.
- The path option is also appended to the native value.
- isTripleSlashed defaults to true.