expo: idToken undefined in result.authentication (authSession with Google)

Summary

When getting a response back from promptAsync using AuthSession with Google, I get an authentication value with an undefined id_token. I know I can get the id_token by itself but I’m looking for both an access token and id_token in the same response because I can’t think of an elegant workaround to get both separately using this library (each would have to prompt the user with a popup, and worse you would have to trigger popups by asking the user to click two buttons or disable pop up blocker)

Managed or bare workflow? If you have ios/ or android/ directories in your project, the answer is bare!

managed

What platform(s) does this occur on?

Web

SDK Version (managed workflow only)

40

Environment

Expo CLI 4.2.1 environment info: System: OS: Linux 5.4 Ubuntu 20.04.2 LTS (Focal Fossa) Shell: 5.0.17 - /bin/bash Binaries: Node: 12.18.1 - ~/.nvm/versions/node/v12.18.1/bin/node Yarn: 1.22.5 - /usr/local/bin/yarn npm: 6.14.5 - ~/.nvm/versions/node/v12.18.1/bin/npm Watchman: 4.9.0 - /usr/bin/watchman npmPackages: expo: ~40.0.0 => 40.0.1 react: 16.13.1 => 16.13.1 react-dom: * => 17.0.2 react-native: https://github.com/expo/react-native/archive/sdk-40.0.1.tar.gz => 0.63.2 react-native-web: ~0.13.12 => 0.13.18 react-navigation: latest => 4.4.4 npmGlobalPackages: expo-cli: 4.2.1 Expo Workflow: managed

Reproducible demo or steps to reproduce from a blank project

Just using the same code as in the docs – but not doing it on snack (since you can’t even enter your credentials there with google sign in). Other people have also seen this bug, see these links: https://stackoverflow.com/questions/66966772/expo-auth-session-providers-google-google-useauthrequest and https://forums.expo.io/t/expo-auth-session-google-useauthrequest-returns-googles-idtoken-value-as-undefined/49510

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Reactions: 15
  • Comments: 31 (3 by maintainers)

Most upvoted comments

Same here: There seems to be a bug in the expo-auth-session/providers/google v 3.2.3 package that returns idToken as undefined when calling Google.useAuthRequest. I’m testing on Expo Go, everything configured correctly as documentation says, web proxy credentials, everything. The only solution that worked for me to get idToken is this code provided by howard:

   const [request, response, promptAsync] = Google.useAuthRequest({
      responseType: "id_token",
      androidClientId: process.env.GOOGLE_CLIENT_ID_ANDROID,
      expoClientId: process.env.GOOGLE_CLIENT_WEB_EXPO,
      scopes: ["email"]
   });

This code is a workaround to get idToken (in the “params” key) and no other data.

The old package expo-google-app-auth seems to be returning idToken correctly along with other data.

Edit: I’ve found Google.useIdTokenAuthRequest that can be used instead of Google.useAuthRequest but seems to do the same thing than the code above. Maybe by design in the package it’s not possible to get idToken and other information at the same time. Also this Google.useIdTokenAuthRequest hook is undocumented except when you click on the firebase tab in the code example of this page

Hi @giacomoalonzi and @kapilpau , I encountered the same issue as you described. After some investigation I discovered my implementation wasn’t correct. Maybe you have the same.

When running on native iOS/Android then the response type is always code (see also Google.ts#L259). The id_token in the response from the promptAsync method will then be empty. Instead, you need to use the id_token parameter in the params from the fullResult variable. See Google.ts#L342.

Here a short example:

const [request, fullResult, promptAsync] = Google.useIdTokenAuthRequest({
  expoClientId: googleExpoClientId,
  iosClientId: googleIosStandaloneClientId,
  androidClientId: googleAndroidStandaloneClientId,
  scopes: ['profile', 'email'],
});

const result = await promptAsync();
if (result.type === 'success') {
  // Token is empty when running on iOS/Android, but filled on Expo
  const token = result.params.id_token;
}

if (fullResult?.type === 'success') {
  // Token is always filled, when running on iOS/Android and when running in Expo
  const token = fullResult.params.id_token;
}

UPDATE: it works on iOS and Expo, but after some more testing on Android I now encounter an issue that the flow ends with {"type":"dismiss"}. See also https://github.com/expo/expo/issues/10860 and https://github.com/expo/expo/issues/12044

Same issues as others. I’m trying to upgrade from expo-google-app-auth -> expo-auth-session. I am not getting both the accessToken and idToken.

I’m using Firebase and it seems as though it doesn’t actually need the idToken, I’m just passing it null. Seems to be working as expected so far. image

Same issue here. Using Google.useAuthRequest and the idToken on the response object is undefind.

This worked for me pretty well

import { View, Text } from 'react-native'
import React, { createContext, useContext } from 'react'
import * as WebBrowser from 'expo-web-browser';
import * as Google from 'expo-auth-session/providers/google';
import {
    GoogleAuthProvider,
    onAuthStateChanged,
    signInWithCredential,
    signOut
} from 'firebase/auth';
import {auth} from "./firebase";

WebBrowser.maybeCompleteAuthSession();

const AuthContext = createContext({});

const config = {
    androidClientId:'',
    expoClientId:'',
    responseType: "id_token"
};

export const AuthProvider = ({ children }) => {
    const [request, response, promptAsync] = Google.useAuthRequest(config);

    async function signInWithGoogle () {
        promptAsync();
    }

    React.useEffect(() => {
        if (response?.type === 'success') {
        const credential = GoogleAuthProvider.credential(id_token);
        signInWithCredential(auth, credential);
        }
      }, [response]);

    return (
        <AuthContext.Provider value={{user:null,signInWithGoogle}}>
            {children}
        </AuthContext.Provider>

    )
};

export default function useAuth() {
    return useContext(AuthContext);
}

same problem

@hitenvats16 see @remcorakers reply above

I tried it but all i got is idToken only dont’know why…

Incurred in the same issue guys, anyone solved the issue?

"expo": "~43.0.4",
"expo-auth-session": "~3.4.2",

this is the response that I get from google

response Object {
  "authentication": null,
  "error": null,
  "errorCode": null,
  "params": Object {
    "authuser": "0",
    "code": "4/0AX4XfWglkpty4fyj0MIfz3402BS6MK4PTCCoWVw5HEkNmIFBZCgKRLZqdx1_ur4_ox5Q-Q",
    "hd": "xxxxxxxxx",
    "prompt": "consent",
    "scope": "email profile https://www.googleapis.com/auth/userinfo.email openid https://www.googleapis.com/auth/userinfo.profile",
    "state": "PqMXFAHpUx",
  },
  "type": "success",
  "url": "ios.myapp:/oauthredirect?state=PqMXFAHpUx&code=4/0AX4XfWglkpty4fyj0MIfz3402BS6MK4PTCCoWVw5HEkNmIFBZCgKRLZqdx1_ur4_ox5Q-Q&scope=email%20profile%20https://www.googleapis.com/auth/userinfo.email%20openid%20https://www.googleapis.com/auth/userinfo.profile&authuser=0&hd=xxxxxxx.com&prompt=consent",
}

as you can see the URL field contains the schema, and if I paste that URL on safari, safari can open my app. So I don’t know if this can help to solve the issue.

Same issue, no access_token or id_token when using native android. Based on the OAuth 2.0 protocol, I can exchange the code for access tokens using the token endpoint https://oauth2.googleapis.com/token(https://developers.google.com/identity/protocols/oauth2/native-app#exchange-authorization-code). This is done by default for web, but for some reason not working for native android.

How can I manually exchange code for access_token using expo-auth-session? Thanks

How I did it was by using shouldAutoExchangeCode see my comment at: https://github.com/expo/expo/issues/18270#issuecomment-1483945639

import Constants, { ExecutionEnvironment } from "expo-constants";

const [request, response, promptAsync] = Google.useIdTokenAuthRequest({
    expoClientId: GOOGLE_PROXY_ID,
    iosClientId: GOOGLE_IOS_ID,
    androidClientId: GOOGLE_ANDROID_ID,
    // ADD THIS TO FORCE THE AUTO EXCHANGE CODE TO GET THE ACCESS TOKEN ONLY WHEN NOT USING THE EXPO GO APP
    shouldAutoExchangeCode:
      Constants.executionEnvironment !== ExecutionEnvironment.StoreClient
        ? true
        : undefined,
  });

useEffect(() => {
    if (response?.type === "success") {
      const { id_token } = response.params;
      console.log(response);
    }
  }, [response]);

Thanks to browniefed on this PR

I managed to get both id_token and access_token by adding the following to useAuthRequest config

 responseType: "id_token token",
 extraParams: {
    nonce: await generateHexStringAsync(16),
 },
 usePKCE: false,

import { generateHexStringAsync } from “expo-auth-session”;

+1 to the question above: is there a way to get the scope (like email, name, etc.) using useIdTokenAuthRequest?

mail’], }); How I can use the scope’s data?

@remcorakers hero! That has worked, thank you!

Hi,

I am using useIdTokenAuthRequest and it works perfectly when using Expo Go, however, when I build an APK (using eas build), params.id_token and authentication are both null. I am providing a valid androidClientId and responseType: "id_token". If anyone has any ideas how to fix this, I’d really appreciate it.

I am also encountering this issue (idToken undefined in result.authentication (authSession with Google) ).

Using managed workflow with expo and expo-auth-session below (the latest ones):

"expo": "~43.0.2", "expo-auth-session": "~3.4.2",

Hello there.

Try sticking to using Google.useIdTokenAuthRequest e.g.

const [request, response, promptAsync] = Google.useIdTokenAuthRequest({
    clientId: "Your Web Client ID",
    androidClientId:"Your Android Client ID",
  });

In your app.json file try add a "scheme": like so…

{
  "expo": {
    "scheme": "somename"
  }
}

If you dont add a scheme. Your stand alone app wont get any data back.

This was mentioned in the AuthSession Documentation but not in the Authentication Guide .