baumblatt / capacitor-firebase-auth

Capacitor Firebase Authentication Plugin
MIT License
261 stars 129 forks source link

Identity provider's (google) token inaccessible & scopes addtion #159

Open beyondszine opened 3 years ago

beyondszine commented 3 years ago

Hi @baumblatt,

first of all thanks for your project. It is really a saver for me. I started out a personal project for an hybrid app & used firebase (angularfire) for it. It was working great for web but eventually ran into app crashing issues when tried to run it on android.

My use case in the app currently requires to fetch contacts from google people api for which I need oauthToken by google. I have gone through #23 but I don't yet think the problem is solved. The only accesstoken being passed through your library is the firbase application/user token & not the google oauth token as per my understanding.(kindly correct if I am mistaken here).

As discussed in #23 you made the alternative but even there for weblayer( i have only gone through this) effectively the googleSignInWeb is called and the function only returns a part of google login response as per here

I tried verifying by putting the same & I am getting the oauthToken like this in the library code. gauth_res_obfsctd

Is this intentional? or there exists certain reason for not returning the entire response object to above layers? Kindly help me out because I need this accessToken to further pass to webviewlayer so as to be able to call google people API.

Also, the other part is, can you tell how do I go about adding the scopes for web based flow. I see that in java code here

kzoltan29 commented 3 years ago

Hi @beyondszine, if you are using Ionic, you can add scopes to capacitor.config.json:

...
"plugins": {
    "SplashScreen": {
      "launchShowDuration": 0
    },
    "CapacitorFirebaseAuth": {
      "providers": ["google.com","facebook.com"],
      "languageCode": "en",
      "nativeAuth": true,
      "permissions": {
           "google": [
              "profile", 
              "https://www.googleapis.com/auth/user.gender.read", 
              "https://www.googleapis.com/auth/user.birthday.read"
            ],
           "facebook":["public_profile", "email", "user_birthday", "user_gender","user_hometown", "user_location"]
       }
    }

I don't know if this helps.

Hi @baumblatt, also a big fan of the library you have built. Thank you so much! I also need the accessToken mentioned above and have been stuck on this issue for a bit. I am on version 2.4.0. The web authentication returns the accessToken, but when I run the authentication through the plugin on the device, I do not get the accessToken back. Any help is appreciated.

beyondszine commented 3 years ago

@kzoltan29 thanks for your comment. Umm, I also did pretty much the same as you did in my forked version. I am able to get the accessToken from native layer too now. So my understanding was incorrect to begin with. There are different ways of Oauth authorization grants. The fundamental way this affects the plugin for our use case is that on native layer, the flow is a tad different(incomplete) from weblayer where SDK is used. (1) So, one have to use auth code along with client id+secret to get the tokens from google api calls. While on web layer, those are returned by default via webapps(javascript) as the user goes through the redirection step & exchange of code->token takes place.

Basic debugging tip for people facing issue: providers' oauth Token looks like : ya29... (like the image above) firebase/providers' access token is a valid JWT.

I used the following code in my firebase functions to make sure I validate accesstoken(if req.) & get oauth tokens from auth code.

import { google } from "googleapis";
import * as functions from "firebase-functions";

const OAuth2 = google.auth.OAuth2;
const functionsConfig : functions.config.Config = functions.config();
console.debug("functions config on start!",functionsConfig);

if( !functionsConfig || !functionsConfig["web"] ){
    let ermsg = "OAuth config not Set";
    console.error(ermsg,functionsConfig);
    throw new Error(ermsg);
}

const webOauthCreds = functionsConfig["web"];

function getOAuthClient() {
    return new OAuth2(webOauthCreds.client_id, webOauthCreds.client_secret);
}

export async function verifyIdToken( oauth2Client:any , oauthIdToken : string ){
    console.debug("verifying id token:",oauth2Client,oauthIdToken);
    let ticket = await oauth2Client.verifyIdToken({
        idToken : oauthIdToken,
        audience: webOauthCreds.web.client_id
    });
    if(!ticket){
        let ermsg = "somehow not ticket is obtained!!"
        console.error(ermsg);
        throw new Error(ermsg);
    }
    return ticket;
}

export function getOauthTokenFromAuthCode(authCode: string){
    var oauth2Client = getOAuthClient();
    return oauth2Client.getToken(authCode);
}

Ref. (1) https://firebase.google.com/docs/auth/web/google-signin#handle_the_sign-in_flow_with_the_firebase_sdk Which clearly states that SDK takes care of complete flow. While android firebase Google login flow doesn't, rather it requires developers to add those steps for server side access.

beyondszine commented 3 years ago

@kzoltan29 also, the capacitor.config.json thing is still lacking the scopes to pass through in case of web layer as you might see in the native signIn java code the google provider takes care of it while in pure web layer it misses it.

beyondszine commented 3 years ago

Hi there, I tried writing post explaining my understanding. Hope it helps somebody BLOG

kzoltan29 commented 2 years ago

Hi @beyondszine, thank you for the writeup - I am back at this. I need an accessToken after Google Authentication to access other Google api's.