2

We are having a flutter app (ios, android, web), where users are signed in via username & password. We are also using google firebase since its powerful and easy to integrate.

The username and password mainly belongs to the website where we are gathering data at. (As example - If they use the website without the app, and they change the password, after that he wont be able to login to the app)

Now the mentionned websites host is giving us API access, login via OpenId to get the access token for the API. Because we are a safety risk since we store the passwort of the users too!

For the API access we dont really need to store Username and password of the user, since they are redundant anyway. But if we want to add a feature (for example message sending or further data storage) we need to have the user signed in into firebase.

Upt to now we are using for (first) signin the following snippet:

 firebaseAuth.createUserWithEmailAndPassword(
          email: email, password: password);

and for already signed in users :

 firebaseAuth.signInWithEmailAndPassword(
              email: email, password: password);

Notice that similar credentials are also using to login on the API. (Since the user is there already registered)

How can we login on firebase with said information without asking twice for a password ond username (once for us, and once for the API) ?

We already tried :

await firebaseAuth.signInWithCustomToken(token)

with the jwl token from the OpenId, of course it did not work because the token did not contain the uid reference.

Daniel Klauser
  • 384
  • 3
  • 16
  • Why do you feel it's necessary to "ask twice for a password ond username". I'm unclear what the problem is here. It might help if you explain further what you did to solve the perceived problem, showing the code for that. Then, explain how you are hoping to improve upon that solution and how you are stuck on that. – Doug Stevenson May 24 '22 at 05:25
  • I updated it with the snippets we are currently using and what we tried. To answer "Why do you feel it's necessary to "ask twice for a password ond username"" : We need to have the user logged in in our App, and the user also needs to be logged in into the API where we get data. Up to now the user uses the same username and pw in the app and in the api. If he changes the username on the api, he wont be able to login anymore and vice versa. – Daniel Klauser May 24 '22 at 06:12
  • It would be more convenient for the user if he would open the app and login to the API and we would somehow generate a username and passwort from the API data. Then we would rely fully on the API and do not store any of the users credentials. – Daniel Klauser May 24 '22 at 06:17
  • 1
    try signinWithCredentials() – Jone Polvora May 24 '22 at 07:53
  • @JonePolvora Do you mean by filling the AuthCredential(providerId: "Someone.com", signInMethod: "username&password", token :"fullJwtroken")? – Daniel Klauser May 24 '22 at 09:20
  • You don't really "sign in" to an API. You sign in the user to your client app, and then you pass that signed-in user's auth token to an API so that it can determine if the user should be able to do what the API normally does. The API can use the admin SDK to validate the credentials before doing what the user requests. – Doug Stevenson May 24 '22 at 12:48
  • I Agree, I came across a solution which I will look more closely. But the main Idea is the following : 1 - Get JwtToken from API ; 2 - Ask Cloud_Function to verify JwtToken and generate a CustomToken via AdminSDK (with id inside token) - 3 SignInWithCustomToken. This way I m only relying on the Id inside the JwtToken. – Daniel Klauser May 24 '22 at 12:59

1 Answers1

2

SOLUTION

Create a Firebase Cloud Function just like described in Firebase Cloud Functions.

Be aware that if you want to create a customtoken, the cloud functions need rights. On initializeApp(..)

admin.initializeApp({
     serviceAccountId: '{App_Name}@appspot.gserviceaccount.com',
 });

So the correct service account has to be selected, you also have to give him the rights to generate tokens. (See => Stackoverflow Question

The Cloud Function does then look the following way :

export const functionName= functions.https.onRequest(async (request, response) => {

const id = request.query.id;
const passcode = request.query.passcode; // not really needed

// add other passcodes for different authentications
if (passcode == "{COMPARE SOMETHING}") {
    await admin.auth().createCustomToken(id).then((customToken) => {
        response.status(200).send({
            'id': id,
            'customToken': customToken
        });
    }).catch((error) => {
        response.status(500).send({
            'ErrorMessage': "No token could be generated",
            "Error": error
        });
    });
}
else {
    response.status(500).send({
        'ErrorMessage': "Passcode wrong"
    });
}
});

On the other hand we have the code on the mobile app :

  // Get JWT Token
  Map<String, dynamic> jwtpayload = 
   Jwt.parseJwt(response_decoded['id_token']); // use import 'package:jwt_decode/jwt_decode.dart';
  final queryParameters = {
    'id': jwtpayload ['sub'],
    'passcode': 'APassCode',
  };
  final uri = Uri.https('us-central1-{yourApp}.cloudfunctions.net',
      '/{functionName}', queryParameters);
  final cloud_function_api_call = await client.post(uri);
  var decoded_cloud_function_api_call =
      jsonDecode(cloud_function_api_call.body);

And at the end :

      await firebaseAuth.signInWithCustomToken(
      decoded_cloud_function_api_call['customToken']);

I hope it helps others facing a similar issue.

Daniel Klauser
  • 384
  • 3
  • 16