Get Started
API Reference


AuthSession is the easiest way to add web browser based authentication (for example, browser-based OAuth flows) to your app, built on top of WebBrowser, Crypto, and Random. If you would like to understand how it does this, read this document from top to bottom. If you just want to use it, jump to the Authentication Guide.

Platform Compatibility

Android DeviceAndroid EmulatoriOS DeviceiOS SimulatorWeb


expo install expo-auth-session

If you're installing this in a bare React Native app, you should also follow these additional installation instructions.

In bare-workflow you can use the uri-scheme package to easily add, remove, list, and open your URIs.
To make your native app handle mycoolredirect:// simply run:
npx uri-scheme add mycoolredirect

You should now be able to see a list of all your project's schemes by running:
npx uri-scheme list

You can test it to ensure it works like this:
# Rebuild the native apps, be sure to use an emulatoryarn iosyarn android
# Open a URI schemenpx uri-scheme open mycoolredirect://some/redirect

  "expo": {
    "scheme": "mycoolredirect"
In order to be able to deep link back into your app, you will need to set a scheme in your project app.config.js, or app.json, and then build your standalone app (it can't be updated with an OTA update). If you do not include a scheme, the authentication flow will complete but it will be unable to pass the information back into your application and the user will have to manually exit the authentication modal (resulting in a cancelled event).

The guides have moved: Authentication Guide.

The typical flow for browser-based authentication in mobile apps is as follows:
  • Initiation: the user presses a sign in button
  • Open web browser: the app opens up a web browser to the authentication provider sign in page. The url that is opened for the sign in page usually includes information to identify the app, and a URL to redirect to on success. Note: the web browser should share cookies with your system web browser so that users do not need to sign in again if they are already authenticated on the system browser -- Expo's WebBrowser API takes care of this.
  • Authentication provider redirects: upon successful authentication, the authentication provider should redirect back to the application by redirecting to URL provided by the app in the query parameters on the sign in page (read more about how linking works in mobile apps), provided that the URL is in the allowlist of allowed redirect URLs. Allowlisting redirect URLs is important to prevent malicious actors from pretending to be your application. The redirect includes data in the URL (such as user id and token), either in the location hash, query parameters, or both.
  • App handles redirect: the redirect is handled by the app and data is parsed from the redirect URL.

The auth.expo.io proxy is only used when startAsync is called, or when useProxy: true is passed to the promptAsync() method of an AuthRequest.

AuthSession handles most of the app-side responsibilities for you:
  • It opens the sign in URL for your authentication provider (authUrl, you must provide it) in a web browser that shares cookies with your system browser.
  • It handles success redirects and extracts all of the data encoded in the URL.
  • It handles failures and provides information to you about what went wrong.

Additionally, AuthSession simplifies setting up authorized redirect URLs by using an Expo service that sits between you and your authentication provider (read Security considerations for caveats). This is particularly valuable with Expo because your app can live at various URLs. In development, you can have a tunnel URL, a lan URL, and a localhost URL. The tunnel URL on your machine for the same app will be different from a co-worker's machine. When you publish your app, that will be another URL that you need to allowlist. If you have multiple environments that you publish to, each of those will also need to be allowlisted. AuthSession gets around this by only having you allowlist one URL with your authentication provider: https://auth.expo.io/@your-username/your-app-slug. When authentication is successful, your authentication provider will redirect to that Expo Auth URL, and then the Expo Auth service will redirect back to your application. If the URL that the auth service is redirecting back to does not match the published URL for the app or the standalone app scheme (eg: exp://expo.dev/@your-username/your-app-slug, or yourscheme://), then it will show a warning page before asking the user to sign in. This means that in development you will see this warning page when you sign in, a small price to pay for the convenience.
How does this work? When you open an authentication session with AuthSession, it first visits https://auth.expo.io/@your-username/your-app-slug/start and passes in the authUrl and returnUrl (the URL to redirect back to your application) in the query parameters. The Expo Auth service saves away the returnUrl (and if it is not a published URL or your registered custom theme, shows a warning page) and then sends the user off to the authUrl. When the authentication provider redirects back to https://auth.expo.io/@your-username/your-app-slug on success, the Expo Auth services redirects back to the returnUrl that was provided on initiating the authentication flow.

If you are authenticating with a popular social provider, when you are ready to ship to production you should be sure that you do not directly request the access token for the user. Instead, most providers give an option to request a one-time code that can be combined with a secret key to request an access token. For an example of this flow, see the Confirming Identity section in the Facebook Login documentation.
Never put any secret keys inside of your app, there is no secure way to do this! Instead, you should store your secret key(s) on a server and expose an endpoint that makes API calls for your client and passes the data back.

import * as AuthSession from 'expo-auth-session';

const [request, response, promptAsync] = useAuthRequest({ ... }, { ... });
Load an authorization request for a code. Returns a loaded request, a response, and a prompt method. When the prompt method completes then the response will be fulfilled.
In order to close the popup window on web, you need to invoke WebBrowser.maybeCompleteAuthSession(). See the Identity example for more info.
If an Implicit grant flow was used, you can pass the response.params to TokenResponse.fromQueryParams() to get a TokenResponse instance which you can use to easily refresh the token.

  • config (AuthRequestConfig) -- A valid AuthRequestConfig that specifies what provider to use.
  • discovery (DiscoveryDocument) -- A loaded DiscoveryDocument with endpoints used for authenticating. Only authorizationEndpoint is required for requesting an authorization code.

  • request (AuthRequest | null) -- An instance of AuthRequest that can be used to prompt the user for authorization. This will be null until the auth request has finished loading.
  • response (AuthSessionResult | null) -- This is null until promptAsync has been invoked. Once fulfilled it will return information about the authorization.
  • promptAsync (function) -- When invoked, a web browser will open up and prompt the user for authentication. Accepts an AuthRequestPromptOptions object with options about how the prompt will execute. You can use this to enable the Expo proxy service auth.expo.io.

const discovery = useAutoDiscovery('https://example.com/auth');
Given an OpenID Connect issuer URL, this will fetch and return the DiscoveryDocument (a collection of URLs) from the resource provider.

  • issuer (string) -- URL using the https scheme with no query or fragment component that the OP asserts as its Issuer Identifier.

  • discovery (DiscoveryDocument | null) -- Returns null until the DiscoveryDocument has been fetched from the provided issuer URL.

Create a redirect url for the current platform and environment. You need to manually define the redirect that will be used in a bare workflow React Native app, or an Expo standalone app, this is because it cannot be inferred automatically.
  • Web: Generates a path based on the current window.location. For production web apps, you should hard code the URL as well.
  • Managed, and Custom workflow: Uses the scheme property of your app.config.js or app.json.
    • Proxy: Uses auth.expo.io as the base URL for the path. This only works in Expo client and standalone environments.
  • Bare workflow: Will fallback to using the native option for bare workflow React Native apps.

  • options (AuthSessionRedirectUriOptions) -- Additional options for configuring the path.

  • redirectUri (string) -- The redirectUri to use in an authentication request.

Fetch a DiscoveryDocument from a well-known resource provider that supports auto discovery.

  • issuer (Issuer) -- An Issuer URL to fetch from.

  • discovery (DiscoveryDocument) -- A discovery document that can be used for authentication.

Exchange an authorization code for an access token that can be used to get data from the provider.

  • config (TokenRequestConfig) -- Configuration used to exchange the code for a token.

  • discovery (DiscoveryDocument) -- A discovery document with a valid tokenEndpoint URL.

Refresh an access token.
  • If the provider didn't return a refresh_token then the access token may not be refreshed.
  • If the provider didn't return a expires_in then it's assumed that the token does not expire.
  • Determine if a token needs refreshed via TokenResponse.isTokenFresh() or shouldRefresh() on an instance of TokenResponse.

  • config (TokenRequestConfig) -- Configuration used to refresh the given access token.

  • discovery (DiscoveryDocument) -- A discovery document with a valid tokenEndpoint URL.

Revoke a token with a provider. This makes the token unusable, effectively requiring the user to login again.

  • config (RevokeTokenRequestConfig) -- Configuration used to revoke a refresh or access token.

  • discovery (DiscoveryDocument) -- A discovery document with a valid revocationEndpoint URL. Many providers do not support this feature.

Initiate an authentication session with the given options. Only one AuthSession can be active at any given time in your application; if you attempt to open a second session while one is still in progress, the second session will return a value to indicate that AuthSession is locked.

  • options (object) --
    A map of options:
    • authUrl (string) -- Required. The URL that points to the sign in page that you would like to open the user to.
    • returnUrl (string) -- The URL to return to the application. In managed apps, it's optional (defaults to ${Constants.linkingUrl}expo-auth-session, for example, exp://expo.dev/@yourname/your-app-slug+expo-auth-session). However, in the bare app, it's required - AuthSession needs to know where to wait for the response. Hence, this method will throw an exception, if you don't provide returnUrl.
    • showInRecents (optional) (boolean) -- (Android only) a boolean determining whether browsed website should be shown as separate entry in Android recents/multitasking view. Default: false

Returns a Promise that resolves to a result object of the following form:
  • If the user cancelled the authentication session by closing the browser, the result is { type: 'cancel' }.
  • If the authentication is dismissed manually with AuthSession.dismiss(), the result is { type: 'dismiss' }.
  • If the authentication flow is successful, the result is {type: 'success', params: Object, event: Object }
  • If the authentication flow is returns an error, the result is {type: 'error', params: Object, errorCode: string, event: Object }
  • If you call AuthSession.startAsync more than once before the first call has returned, the result is {type: 'locked'}, because only one AuthSession can be in progress at any time.

Cancels an active AuthSession if there is one. No return value, but if there is an active AuthSession then the Promise returned by the AuthSession.startAsync that initiated it resolves to { type: 'dismiss' }.

AuthSession.getRedirectUrl(extraPath?: string): string
Get the URL that your authentication provider needs to redirect to. For example: https://auth.expo.io/@your-username/your-app-slug. You can pass an additional path component to be appended to the default redirect URL.
Note This method will throw an exception if you're using the bare workflow on native.
const url = AuthSession.getRedirectUrl('redirect');

// Managed: https://auth.expo.io/@your-username/your-app-slug/redirect
// Web: https://localhost:19006/redirect

Load an authorization request for a code.

  • config (AuthRequestConfig) -- A valid AuthRequestConfig that specifies what provider to use.
  • discovery (IssuerOrDiscovery) -- A loaded DiscoveryDocument or issuer URL. (Only authorizationEndpoint is required for requesting an authorization code).

  • request (AuthRequest) -- An instance of AuthRequest that can be used to prompt the user for authorization.

Used to manage an authorization request according to the OAuth spec: Section 4.1.1. You can use this class directly for more info around the authorization.
Common use-cases
  • Parse a URL returned from the authorization server with parseReturnUrlAsync().
  • Get the built authorization URL with makeAuthUrlAsync().
  • Get a loaded JSON representation of the auth request with crypto state loaded with getAuthRequestConfigAsync().
// Create a request.
const request = new AuthRequest({ ... });

// Prompt for an auth code
const result = await request.promptAsync(discovery, { useProxy: true });

// Get the URL to invoke
const url = await request.makeAuthUrlAsync(discovery);

// Get the URL to invoke
const parsed = await request.parseReturnUrlAsync("<URL From Server>");

Represents an authorization response error: Section 5.2. Often times providers will fail to return the proper error message for a given error code. This error method will add the missing description for more context on what went wrong.

Object returned after an auth request has completed.
typestringHow the auth completed 'cancel', 'dismiss', 'locked', 'error', 'success'.Code
urlstringAuth URL that was opened
errorAuthError | nullPossible error if the auth failed with type error
paramsRecord<string, string>Query params from the url as an object
errorCodestring | nullLegacy error code query param, use error instead
  • If the user cancelled the auth session by closing the browser or popup, the result is { type: 'cancel' }.
  • If the auth is dismissed manually with AuthSession.dismiss(), the result is { type: 'dismiss' }.
  • If the auth flow is successful, the result is {type: 'success', params: Object, event: Object }
  • If the auth flow is returns an error, the result is {type: 'error', params: Object, errorCode: string, event: Object }
  • If you call promptAsync() more than once before the first call has returned, the result is {type: 'locked'}, because only one AuthSession can be in progress at any time.

The client informs the authorization server of the desired grant type by using the a response type: Section 3.1.1.
CodeFor requesting an authorization codeSection 4.1.1.
TokenFor requesting an access token (implicit grant)Section 4.2.1
IdTokenCustom for Google OAuth ID Token authN/A

Represents an OAuth authorization request as JSON.
responseTypeResponseType | stringSpecifies what is returned from the authorization server.CodeSection 3.1.1
clientIdstringUnique ID representing the info provided by the clientSection 2.2
redirectUristringThe server will redirect to this URI when completeSection 3.1.2
promptPromptShould the user be prompted to login or consent again.Section
scopesstring[]List of strings to request access toSection 3.3
clientSecret?stringClient secret supplied by an auth providerSection 2.3.1
codeChallengeMethodCodeChallengeMethodMethod used to generate the code challenge.S256Section 6.2
codeChallenge?stringDerived from the code verifier using the CodeChallengeMethodSection 4.2
state?stringUsed for protection against Cross-Site Request ForgerySection 10.12
usePKCE?booleanShould use Proof Key for Code ExchangetruePKCE
extraParams?Record<string, string>Extra query params that'll be added to the query stringN/A

Options passed to the promptAsync() method of AuthRequests.
useProxy?booleanShould use auth.expo.io proxy for redirecting requests. Only works in managed native appsfalse
showInRecents?booleanShould browsed website be shown as a separate entry in Android multitaskerfalse
url?stringURL that'll begin the auth request, usually this should be left undefinedPreloaded value

S256The default and recommended method for transforming the code verifier.
PlainWhen used, the code verifier will be sent to the server as-is.

Informs the server if the user should be prompted to login or consent again. This can be used to present a dialog for switching accounts after the user has already been logged in. You should use this in favor of clearing cookies (which is mostly not possible on iOS).
NoneServer must not display any auth or consent UI. Can be used to check for existing auth or consent.login_required, interaction_required
LoginServer should prompt the user to reauthenticate.login_required
ConsentServer should prompt the user for consent before returning information to the client.consent_required
SelectAccountServer should prompt the user to select an account. Can be used to switch accounts.account_selection_required

Grant type values used in dynamic client registration and auth requests.
AuthorizationCodeUsed for exchanging an authorization code for one or more tokens.
ImplicitUsed when obtaining an access token.
RefreshTokenUsed when exchanging a refresh token for a new token.
ClientCredentialsUsed for client credentials flow.

A hint about the type of the token submitted for revocation. If not included then the server should attempt to deduce the token type.
AccessTokenProvided an access token.
RefreshTokenProvided a refresh token.

authorizationEndpoint?stringInteract with the resource owner and obtain an authorization grantSection 3.1
tokenEndpoint?stringObtain an access token by presenting its auth grant or refresh tokenSection 3.2
revocationEndpoint?stringUsed to revoke a token (generally for signing out)Section 2.1
userInfoEndpoint?stringURL to return info about the authenticated userUserInfo
endSessionEndpoint?stringURL to request that the End-User be logged out at the OP.OP Metadata
registrationEndpoint?stringURL of the OP's "Dynamic Client Registration" endpointDynamic Client Registration
discoveryDocumentProviderMetadataAll metadata about the providerProviderMetadata

Shared properties for token requests (refresh, exchange, revoke).
clientIdstringUnique ID representing the info provided by the client
clientSecret?stringClient secret supplied by an auth provider
extraParams?Record<string, string>Extra query params that'll be added to the query string
scopes?string[]List of strings to request access to

Extends TokenRequestConfig meaning all properties of TokenRequestConfig can be used.
Config used to exchange an authorization code for an access token.
codestringThe authorization code received from the authorization server.Section 3.1
redirectUri?stringIf the redirectUri parameter was included in the AuthRequest, then it must be supplied here as well.Section 3.1.2

Extends TokenRequestConfig meaning all properties of TokenRequestConfig can be used.
Config used to request a token refresh, or code exchange.
refreshTokenstringThe refresh token issued to the client.

Extends Partial<TokenRequestConfig> meaning all properties of TokenRequestConfig can optionally be used.
Used for revoking a token.
tokenstringThe token that the client wants to get revoked.Section 3.1
tokenTypeHint?TokenTypeHintA hint about the type of the token submitted for revocation.Section 3.2

Type: string
URL using the https scheme with no query or fragment component that the OP asserts as its Issuer Identifier.

Metadata describing the OpenID Provider.

Options passed to makeRedirectUriAsync.
native?stringThe URI scheme that will be used in a bare React Native or standalone Expo app
path?stringOptional path to append to a URI
preferLocalhost?booleanAttempt to convert the Expo server IP address to localhost. Should only be used with iOS simulators
useProxy?booleanShould use the auth.expo.io proxy

Access token type Section 7.1
'bearer' | 'mac'

In managed apps, AuthSession uses Expo servers to create a proxy between your application and the auth provider. Unfortunately, we don't provide support to use these servers in bare apps. To overcome this, you can create your proxy service.

This service is responsible for:
  • redirecting traffic from your application to the authentication service
  • redirecting response from the auth service to your application using a deep link
To better understand how it works, check out this implementation in node.js:
const http = require('http');
const url = require('url');

const PORT = PORT;

function redirect(response, url) {
  response.writeHead(302, {
    Location: url,

  .createServer((request, response) => {
    // get parameters from request
    const parameters = url.parse(request.url, true).query;

    // if parameters contain authServiceUrl, this request comes from the application
    if (parameters.authServiceUrl) {
      // redirect user to the authUrl
      redirect(response, decodeURIComponent(parameters.authServiceUrl));

    // redirect response from the auth service to your application
    redirect(response, DEEP_LINK);
Client code which works with this service:
const authServiceUrl = encodeURIComponent(YOUR_AUTH_URL); // we encode this, because it will be send as a query parameter
const authServiceUrlParameter = `authServiceUrl=${authUrl}`;
const authUrl = `YOUR_PROXY_SERVICE_URL?${authServiceUrlParameter}`;
const result = await AuthSession.startAsync({
  returnUrl: YOUR_DEEP_LINK,

There are many reasons why you might want to handle inbound links into your app, such as push notifications or just regular deep linking (you can read more about this in the Linking guide); authentication redirects are only one type of deep link, and AuthSession handles these particular links for you. In your own Linking.addEventListener handlers, you can filter out deep links that are handled by AuthSession by checking if the URL includes the +expo-auth-session string -- if it does, you can ignore it. This works because AuthSession adds +expo-auth-session to the default returnUrl; however, if you provide your own returnUrl, you may want to consider adding a similar identifier to enable you to filter out AuthSession events from other handlers.

If you are using deep linking with React Navigation v5, filtering through Linking.addEventListener will not be sufficient, because deep linking is handled differently. Instead, to filter these events you can add a custom getStateFromPath function to your linking configuration, and then filter by URL in the same way as described above.