Productivity Tools

Tools written by an IT business manager, a passionate developer.

FirebaseAuthentication

This example shows how to use Firebase Authentication in two scenarios:

Diagram below presents all compoonents of the solution.

Arch

CloudRunPythonBackend

We have folowing resources

Firebase configuration

I choosed only the google provider

After creating project we need to add apps. We add web app

Console provides us snipped which should be added to our application

Next we need to add to our application code responsible for opening google login page it is described here

import { getAuth, signInWithPopup, GoogleAuthProvider } from "firebase/auth";

const auth = getAuth(app);

const googleProvider = new GoogleAuthProvider();
const signInWithGoogle = async () => {
    try {
        debugger;
        const res = await signInWithPopup(auth, googleProvider);
        console.log(res);
    } catch (err) {
        console.error(err);
        alert(err.message);
    }
};

Service account

To validate token we need to create firebase app. To do it we need to reference service account key. We can create application without any parameters default_app=initialize_app() then application will look for the file path under environment variable GOOGLE_APPLICATION_CREDENTIALS. In our example I will load service account key from drive.

Download service account key:

Service account key

Token validation

Probably there is more ‘pro’ way of validating token, I did it quick and dirty: auth.verify_id_token() returns data if token is correct and throws exception if not.

class ProtectedDateResource(Resource):
    def get(selfs):
        id_token=request.headers.environ["HTTP_AUTHORIZATION"]
        id_token=id_token.replace("Bearer","")
        id_token=id_token.replace(" ","")
        decoded_token=auth.verify_id_token(id_token)
        today=datetime.now()
        tstr=today.strftime('%m/%d/%Y %H:%m:%S')
        return tstr,HTTPStatus.OK

Our service should work

Console app

Console app do not have an interface in which we could login, so we need to create a customtoken on the server side and return it to the consol app. Then console app will take this custom_token and ask server with it to obtain access_token

Token service in backend app

It is easy we are creating endpoint which will return us token

class TokenResource(Resource):
    def get(self):
        custom_token=auth.create_custom_token("password123");
        return Response(custom_token, mimetype="text/plain",direct_passthrough=True)

Console app

To call the service first we get custom token, next with this custom token we are calling for the access_token and then for the resource.

string custom_token = await CustomToken.GetCustomToken();
Console.WriteLine($"Custom token: {custom_token}");
string access_token = await AccessToken.GetAccesToken(custom_token);
Console.WriteLine($"Access token: {access_token}");
string result = await RestService.GetResource(access_token);
Console.WriteLine(result);
Console.ReadLine();

Access token is retrieved from googleapis. To get it we need to call for the given adddress with Web API Key in the query

public static async Task<string> GetAccesToken(string custom_token)
{
    var HttpClient = new HttpClient();
    Uri url = new Uri(@"https://identitytoolkit.googleapis.com/v1/accounts:signInWithCustomToken?key=AIzaSyDgSHqUdtL0XQ1i95Y_fMKTHV48Yjo_ZWs");

    HttpClient.DefaultRequestHeaders.Accept.Clear();
    HttpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

    object obj = new { token = custom_token, returnSecureToken = true };
    var dataAsString = JsonConvert.SerializeObject(obj);
    var content = new StringContent(dataAsString, Encoding.UTF8, "application/json");

    HttpResponseMessage response = await HttpClient.PostAsync(url, content);
    if (response.IsSuccessStatusCode)
    {
        var resultAsString = await response.Content.ReadAsStringAsync();
        AccessToken result = JsonConvert.DeserializeObject<AccessToken>(resultAsString);
        return result.idToken;
    }
    throw new Exception(response.ReasonPhrase);
}

Working application:

Close Bitnami banner
Bitnami