Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Authenticating via Firebase on Android #149

Closed
Sebastian-Neubert opened this issue Oct 8, 2020 · 31 comments
Closed

Authenticating via Firebase on Android #149

Sebastian-Neubert opened this issue Oct 8, 2020 · 31 comments
Labels
help wanted Extra attention is needed

Comments

@Sebastian-Neubert
Copy link

Hello there,

I have successfully set up the Firebase login process on iOS but is there a way to do this on Android as well? I tried passing the id_token and the code to AppleAuthProvider.credential() but that resulted in this error:

Something unexpected happened while signing in with Apple NativeFirebaseError: [auth/invalid-credential] The supplied auth credential is malformed, has expired or is not currently supported.

Am I missing something or is it actually not possible at the moment?

Regards

@mikehardy
Copy link
Collaborator

I'm not sure anyone has tried it, you might be first! Unfortunately that means you are the current leading edge of knowledge in the area 😅

@mikehardy
Copy link
Collaborator

This is definitely one of those issues in between the two libraries but might be best in the react-native-firebase library,

It is supposed to work thought now that I look more deeply:

https://github.com/invertase/react-native-firebase/blob/b84e718f15b9254cffb0202ea956e47014c181a2/packages/auth/android/src/main/java/io/invertase/firebase/auth/ReactNativeFirebaseAuthModule.java#L1400

@dburdan - did you integrate with react-native-firebase for Android Apple auth or are you using something else? If so, do you have it working and it's just an API usage issue here? If not, we'll keep digging

@Sebastian-Neubert the best I can suggest is going into node_modules around the line that I linked there and logging out all the inputs and outputs to the underlying API call to start tracing the data and comparing it vs the assumptions in the code to see where things go off the rails

@dburdan
Copy link
Contributor

dburdan commented Oct 10, 2020

@mikehardy My implementation was fully bespoke; I'm unfamiliar with Firebase Auth or the RN library, but I'm happy to lend a hand here.

@Sebastian-Neubert Did you pass your nonce value through to Firebase? If I'm not mistaken, I believe Firebase needs just the id_token and nonce.

@Sebastian-Neubert
Copy link
Author

@dburdan In the iOS implementation I indeed passed the id_token and nonce to Firebase but on Android I don't get a value named nonce from the library. The only available values in the response are: user, state, code and id_token

@dburdan
Copy link
Contributor

dburdan commented Oct 11, 2020

Have you tried generating the nonce before hand and providing it to both libraries as seen in the Android example? The nonce can be any unique, random set of characters, like a UUID.

I will take a deeper look at the return values on Android to make sure they match iOS.

@Sebastian-Neubert
Copy link
Author

No, I haven't generated the nonce before hand. The iOS-part of the library does that somehow automatically and provides it for me.

@ghivert
Copy link

ghivert commented Oct 15, 2020

Hi, I was stuck with the same problem. I got it working like this:

const getRandomString = length => {
  let randomChars =
    'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
  let result = ''
  for (let i = 0; i < length; i++) {
    result += randomChars.charAt(Math.floor(Math.random() * randomChars.length))
  }
  return result
}

export const appleLogin = async () => {
  return Platform.select({
    ios: iosAppleLogin(),
    android: androidAppleLogin(),
  })
}

const iosAppleLogin = async () => {
  const appleAuthRequestResponse = await appleAuth.performRequest({
    requestedOperation: appleAuth.Operation.LOGIN,
    requestedScopes: [appleAuth.Scope.EMAIL, appleAuth.Scope.FULL_NAME],
  })
  if (!appleAuthRequestResponse.identityToken) {
    throw 'Apple Sign-In failed - no identify token returned'
  }
  const { identityToken, nonce } = appleAuthRequestResponse
  const appleCredential = auth.AppleAuthProvider.credential(
    identityToken,
    nonce,
  )
  return auth().signInWithCredential(appleCredential)
}
const androidAppleLogin = async () => {
  // Generate secure, random values for state and nonce
  const rawNonce = getRandomString(20)
  const state = getRandomString(20)

  // Configure the request
  appleAuthAndroid.configure({
    clientId: 'THE SAME SERVICE ID AS APPLE DEV AND FIREBASE CONSOLE',
    redirectUri: 'THIS IS THE SAME AS APPLE DEV CONSOLE',
    responseType: appleAuthAndroid.ResponseType.ALL,
    scope: appleAuthAndroid.Scope.ALL,
    nonce: rawNonce,
    state,
  })
  const response = await appleAuthAndroid.signIn()
  if (response.state === state) {
    const credentials = auth.AppleAuthProvider.credential(
      response.id_token,
      rawNonce, // Passing the rawNonce here do the trick.
    )
    return auth().signInWithCredential(credentials)
  }
}

The idea is to generate the nonce ourselves and just passing it to Firebase to let it check if what give Apple is the same as what we give in the nonce.

@mikehardy
Copy link
Collaborator

Appears this might a documentation / example issue then, or we could decide to handle it internally for Android. I'd take PRs for either

for iOS we do handle it internally (with the ability to disable) - here's a PR that added the ability to disable nonce for ios if people are interested in seeing all the places nonce is touched #52

@mikehardy mikehardy added help wanted Extra attention is needed and removed waiting for feedback labels Oct 15, 2020
@dburdan
Copy link
Contributor

dburdan commented Oct 17, 2020

I submitted a PR (#153) that adds support for automatic nonce generation on Android. While I ran it through various tests, I don't personally use this feature, so additional checks would be appreciated.

Hopefully this provides more parity with the iOS half of the library.

@alesmraz
Copy link

Hi, i'm facing this issue too. I try to go by documentation and by @ghivert answer but without success. Is there someone with working solution for Firebase? 🙏

web login is open, user fill login info and function await appleAuthAndroid.signIn() return object with some data (user, state, code and id_token). But when i try to set this data into auth().signInWithCredential() function then it return error: The supplied auth credential is malformed, has expired or is not currently supported.

I know this is not stackoverflow but...

there is my code and Firebase config:

import { appleAuthAndroid } from '@invertase/react-native-apple-authentication'
import uuid from 'uuid'

const rawNonce = uuid()
const state = uuid()

appleAuthAndroid.configure({
	clientId: 'APPLE_CLIENT_ID',
	redirectUri: 'REDIRECT_CALLBACK',
	responseType: appleAuthAndroid.ResponseType.ALL,
	scope: appleAuthAndroid.Scope.ALL,
	nonce: rawNonce,
	state,
})

const response = await appleAuthAndroid.signIn()

if (response.state === state && response.id_token) {
	const providerData = auth.AppleAuthProvider.credential(
					response.id_token,
					rawNonce // or response.code -> without success
	)

	await auth().signInWithCredential(providerData)
} else {
	throw new Error('Apple sign-in error')
}

Screenshot 2020-10-20 at 15 46 45

Packages:
...
"@invertase/react-native-apple-authentication": "^2.0.2",
"@firebase/auth": "^0.13.5",
"react-native": "0.63.2"
...

@ghivert
Copy link

ghivert commented Oct 20, 2020

Hi @alesmraz,

It looks like an issue with Firebase. Are you sure you provide the Apple Service ID in Firebase Dashboard ? You can find it on Apple Developers Dashboard under service section. I had this error at first because I was providing bundle app ID and not service ID.

Edit : are your OAuth settings completed too ?

@Sebastian-Neubert
Copy link
Author

It still does not work for me as well. I have everything set up correctly (I guess), even the OAuth settings, but I always get the error:

AppleAuth is not supported on the device. Currently Apple Authentication works on iOS devices running iOS 13 or later. Use 'AppleAuth.isSupported' to check...

@mikehardy
Copy link
Collaborator

@Sebastian-Neubert

{appleAuthAndroid.isSupported && (

@Sebastian-Neubert
Copy link
Author

Sebastian-Neubert commented Oct 20, 2020

@mikehardy But why is it not supported in my case? What could be the reasons?

@mikehardy
Copy link
Collaborator

@Sebastian-Neubert it is, that line runs and executes correctly. Note it is on a different imported type

@Sebastian-Neubert
Copy link
Author

@mikehardy You are right, it is supported. But the login with Firebase does still not work. Even the solution from @ghivert does not work for me.

@alesmraz
Copy link

@ghivert Thanks for advice! I double checked configuration in Firebase and Apple Developers and it's same. I also try hash (SHA256) nonce before go to apple service server but without success. Also function isSupported return true.

OAuth setting is completed. We already has Apple auth on web (not React native) connected to same firebase without any issues. I assume that is work same (please correct me if its wrong) on web and on non-apple devices?

@ghivert
Copy link

ghivert commented Oct 22, 2020

Hum, that’s weird… It should work in the same for web and Android because it uses OAuth to authenticate in a web-browser. In Android, it’s just a matter of handling the redirect URL correctly.

The error The supplied auth credential is malformed, has expired or is not currently supported. seems like an issue with Firebase itself if await appleAuthAndroid.signIn() is working. I think Apple is sending correct informations, but Firebase is not handling them as needed. I had this error when Firebase Auth wasn’t properly configured. I would say that you should double-check Firebase Auth with Apple IDs and Key IDs, and if it really doesn’t work, try to ask the Firebase team directly? If appleAuthAndroid.signIn() is working, then it’s not a bug with react-native-apple-authentication.

@matthova
Copy link

@alesmraz any luck? I'm stuck on the same workflow.

@Samaritan1011001
Copy link

@alesmraz
I think it is not a firebase issue. The Apple sign in on iOS also uses firebase's signInWithCredential and it works.
I tried using a predefined nonce like the example above but having the same problem.
Does it have to do something with the id_token we get back as response from await appleAuthAndroid.signIn() ?

@MattHorriganSunrise
Copy link

MattHorriganSunrise commented Nov 4, 2020

Also having the same issue with Android Apple Sign in. (Works with iOS I get the UID from Firebase just fine)

const response = await appleAuthAndroid.signIn();
const { id_token } = response;

const androidCredential = firebase.auth.OAuthProvider.credential(
  id_token,
  rawNonce,
);

const userCredential = await firebase
  .auth()
  .signInWithCredential(androidCredential);

Looks like I get everything I need with androidCredential the:

providerId: string;
token: string;
secret: string;

but the userCredential doesn't return a UID from Firebase like it does Apple, it doesn't return anything nor does it register the user in the Firebase console.

Followed this https://github.com/invertase/react-native-apple-authentication/blob/master/example/app.android.js#L61

This seems like an issue with firebase.auth().signInWithCredential() not with react-native-apple-authentication

@mikehardy
Copy link
Collaborator

I think you have to decode the idtoken - see #160

@Samaritan1011001
Copy link

@mikehardy decode the id_token how? That comment in the issue you shared does not mention that.

@ghivert
Copy link

ghivert commented Nov 13, 2020

Did you try with firebase.auth.AppleAuthProvider.credential instead of firebase.auth.OAuthProvider.credential? I think the AppleAuthProvider does the decoding work for you.

@Horus888
Copy link

Horus888 commented Jan 9, 2021

I was stuck with the same problem.

@Shaninnik
Copy link

For me adding correct Services ID to firebase apple auth settings solved the issue, it is optional for iOS so I had it empty. I am using auth.AppleAuthProvider.credential and generate nonce manually. Can confirm that it works, if you see apple login page but get the The supplied auth credential is malformed, has expired or is not currently supported. then it is probably some issue with your configs.

@isaactan001
Copy link

isaactan001 commented Jul 7, 2021

I am implementing sign in with Apple. I can successfully see the Apple login page. I key in the correct credentials. It should be able to sign in/sign up to the firebase based on the returned value from Apple.

However I am getting this error Error: The supplied auth credential is malformed, has expired or is not currently supported. Something must be wrong at the firebase side? You may refer to the onPressAppleLogin function below on the logic. Many thanks!

What I have done:

In Firebase

  1. Authentication with Sign-in provider Apple enabled
  2. My service id is co.myexampleapp.signinwithapple
  3. My authorization callback is https://my-example-app.firebaseapp.com/__/auth/handler

In developer.apple.com

  1. I created a service id co.myexampleapp.signinwithapple with the service Sign In with Apple enabled
  2. I added my-example-app.firebaseapp.com for the Domain and https://my-example-app.firebaseapp.com/__/auth/handler in the Return URLs

My React Native source code

import { appleAuthAndroid } from '@invertase/react-native-apple-authentication';
import firebase from 'react-native-firebase'

getRandomString = (length: any) => {
    let randomChars =
        'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
    let result = ''
    for (let i = 0; i < length; i++) {
        result += randomChars.charAt(Math.floor(Math.random() * randomChars.length))
    }
    return result
}

onPressAppleLogin = async () => {
    const rawNonce = this.getRandomString(20);
    const state = this.getRandomString(20)

    appleAuthAndroid.configure({
        clientId: 'co.myexampleapp.signinwithapple',
        redirectUri: 'https://my-example-app.firebaseapp.com/__/auth/handler',
        responseType: appleAuthAndroid.ResponseType.ALL,
        scope: appleAuthAndroid.Scope.ALL,
        nonce: rawNonce,
        state,
    });

    const response = await appleAuthAndroid.signIn();

    const appleCredential = await firebase.auth.AppleAuthProvider.credential(response.id_token, rawNonce)

    const appleUserCredential = await firebase.auth().signInWithCredential(appleCredential) // error happens here!
}

@ghivert
Copy link

ghivert commented Jul 8, 2021

It looks like you're using an old version of Firebase. You should try with the latest up to date package @react-native-firebase/auth instead of react-native-firebase.

@isaactan001
Copy link

@ghivert Hi, I may not feasible to perform the upgrade as it will cause breaking changes. Currently my version is "react-native-firebase": "^5.6.0", may I know what's your working version?

@ghivert
Copy link

ghivert commented Jul 14, 2021

I’m using "@react-native-firebase/auth": "^12.0.0"
It will be hard for you if you stay out of sync with the packages.

@mikehardy
Copy link
Collaborator

Happy to take PRs to resolve issues / extend functionality but as current maintainer the library currently handles my use cases, which means I do not have an interest in volunteering unpaid labor myself for use cases I don't need.

Happy to take those PRs and merge them though if anyone paying attention to this issue is motivated to develop them.

In the meantime closing this as stale

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests