Google authentication


#1

I am trying to sign in with Google but have error:

Your request parameters did not validate.

I have registered the app in Google api console, and i have receiving token when the user sign in.

Task<GoogleSignInAccount> task = GoogleSignIn.getSignedInAccountFromIntent(data);
           
               GoogleSignInAccount mAccount = task.getResult(ApiException.class);

                String idToken = mAccount.getIdToken();
              

then i pass this token to SyncCredentials.google(token)

public void login(String token, boolean isAdmin) {

        SyncCredentials credentials = SyncCredentials.google(token);

        SyncUser.logInAsync(credentials, AppConsts.AUTH_URL, new SyncUser.Callback<SyncUser>() {

            @Override
            public void onSuccess(@NonNull SyncUser user) {
                Log.d(TAG, "onSuccess: ");
                userLoggedIn();
            }

            @Override
            public void onError(@NonNull ObjectServerError error) {
                Log.d(TAG, "onError: " + error.getErrorMessage());
            }
        });
    }

What i missed?


#2

Are you trying to use the google provider against cloud? If that’s the case, then it is not possible as it has not been enabled on cloud yet. What you can do is create a lambda function that validates the google token and issues a JWT. Alternatively, you can use a third party service, such as auth0 that will do that for you and you can then pass the JWT to the Realm Object Server.


#3

I don’t really understand how to create lambda that validates Google token? where i can find example? also JWT requires public key, from where i need to get this key? there docs in not really informative about this topic.


#4

This is typescript, but I imagine it should be easy to translate to regular javascript:

import * as superagent from "superagent";
import * as jwt from "jsonwebtoken";
import * as fs from "fs-extra";

export class GoogleAuthenticator {
    private key = fs.readFileSync("path-to-private-key.pem", { encoding: "utf8" });

    public async authenticate(accessToken: string) {
        const response = await superagent.get(`https://www.googleapis.com/oauth2/v3/tokeninfo?id_token=${accessToken}`)
            .set("Accept", "application/json");

        if (response.body.sub === undefined ||
            response.body.aud !== this.clientId) {
            throw new Error("Invalid Credentials");
        }

        const now = Math.floor(Date.now() / 1000);
        if (parseInt(response.body.exp, 10) <= now) {
            throw new Error("Token is expired.");
        }

        // First check for the user to perform standard login
        const payload = { userId: response.body.sub.toString() };
        const token = jwt.sign(payload, this.key, { algorithm: "RS256"});
        return token;
    }
}

#5

I think this process need to be done in backed, especially storing private key, i am developing on Android client side.


#6

Yes, this is something that supposedly happens in a lambda/azure function - that would be easiest/cheapest. You can of course host a minimal web server for it, but that’ll likely be a little more involved. But you’re right - you need something on the backend that validates the google token and signs a jwt.


#7

Okay, thanks for your time!