EXPO AuthSession returns dismiss on Android device
Asked Answered
M

2

6

I'm using Expo AuthSession to login in my app through my IdentityServer4 implementation.

I have the problem only in ANDROID when I try to log in my IdentityServer with my Google account.

The AuthSession open the browser in my device and I'm able to log in but after, when I answer YES to the notification that ask me if I want to allow the access I receive dismiss in my React Native App.

I noticed that if I register before my google account in the browser the problem disappear and I'm able to log in.

The code that I'm using is like this:

import * as AuthSession from "expo-auth-session";
import jwtDecode from "jwt-decode";
import * as React from "react";
import { Alert, Button, Platform, StyleSheet, Text, View } from "react-native";

// You need to swap out the Auth0 client id and domain with the one from your Auth0 client.
// In your Auth0 client, you need to also add a url to your authorized redirect urls.
//
// For this application, I added https://auth.expo.io/@arielweinberger/with-auth0 because I am
// signed in as the "arielweinberger" account on Expo and the name/slug for this app is "with-auth0".
//
// You can open this app in the Expo client and check your logs to find out your redirect URL.

const auth0ClientId = "ppSP6KhARumIUKQl5J02GTABifmBdDGy";
const auth0Domain = "expo-auth0.us.auth0.com"
const authorizationEndpoint = `https://${auth0Domain}/authorize`;

const useProxy = Platform.select({ default: false });
const redirectUri = AuthSession.makeRedirectUri({ useProxy, native:"myapp://" });

export default function App() {
  const [name, setName] = React.useState(null);

  const [request, result, promptAsync] = AuthSession.useAuthRequest(
    {
      redirectUri,
      clientId: auth0ClientId,
      // id_token will return a JWT token
      responseType: "id_token",
      // retrieve the user's profile
      scopes: ["openid", "profile"],
      extraParams: {
        // ideally, this will be a random value
        nonce: "nonce",
      },
    },
    { authorizationEndpoint }
  );

  // Retrieve the redirect URL, add this to the callback URL list
  // of your Auth0 application.
  console.log(`Redirect URL: ${redirectUri}`);

  React.useEffect(() => {
    if (result) {
      if (result.error) {
        Alert.alert(
          "Authentication error",
          result.params.error_description || "something went wrong"
        );
        return;
      }
      if (result.type === "success") {
        // Retrieve the JWT token and decode it
        const jwtToken = result.params.id_token;
        const decoded = jwtDecode(jwtToken);

        const { name } = decoded;
        setName(name);
      }
    }
  }, [result]);

  return (
    <View style={styles.container}>
      {name ? (
        <Text style={styles.title}>You are logged in, {name}!</Text>
      ) : (
        <Button
          disabled={!request}
          title="Log in with Auth0"
          onPress={() => promptAsync({ useProxy })}
        />
      )}
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "#fff",
    alignItems: "center",
    justifyContent: "center",
  },
  title: {
    fontSize: 20,
    textAlign: "center",
    marginTop: 40,
  },
});
Morelos answered 6/2, 2021 at 18:45 Comment(0)
M
12

I solved. When I call promptAsync I can add some options and one of these is showInRecents (Should browsed website be shown as a separate entry in Android multitasker) the default is false. Setting this to true solved my problem.

promptAsync(discovery, { useProxy, showInRecents:true });
Morelos answered 8/2, 2021 at 20:21 Comment(2)
GREAT SOLUTION! This flag showInRecents: true also allows user to switch to diff app in the middle of authenticating, (perhaps to check an authenticator for 2FA), then switch back without losing the previous web progress. Otherwise the web browser session tends to "close" itself & you'll have to restart from the beginning.Walkthrough
Thank God for this solution - the only way to make MFA/2FA authentication work when you have to minimize the app.Nolitta
M
0

If you are still encountering this problem, as of September 2024, my solution was to get the link manually, and then process the authentication flow.

Note: This use effect only gets triggered on Android, not in IOS (For IOS I still use the useAuthRequest hook, it still works just fine.)

Here is what I did:


//region: Get Link When Redirecting

import { Linking } from "react-native";

import React, { useEffect } from "react";

useEffect(() => {

const handleURL = (event: { url: string }) => {

if (event.url) {

const params = event.url.split("?")[1];

const paramsObject = Object.fromEntries(new URLSearchParams(params));

// continue here...

// ( What I did on my end was that I saved this to a Redux State \

// and continue the authentiAcation process from there )

}

};

const linking_listener = Linking.addEventListener("url", handleURL);

return () => {

linking_listener.remove();

};

});

Mown answered 2/9, 2024 at 13:10 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.