Secure Cloud Functions With Firebase Authentication (Python)

from flask import abortfrom firebase_admin import authdef test_firebase_auth(request):    authorization = request.headers.get('Authorization')    # authorization = request.headers['Authorization']    id_token = None    if authorization and authorization.startswith('Bearer '):        id_token = authorization.split('Bearer ')[1]    else:        abort(401)    try:        decoded_token = auth.verify_id_token(id_token)        uid = decoded_token['uid']        # log.info(decoded_token)        return uid    except Exception as e: # ValueError or auth.AuthError        abort(401)

requirements.txt

# https://pypi.org/project/firebase-admin/
firebase-admin==2.16.0

Test Firebase Auth from Web/Javascript

Create another cloud functions to serve html/javascript to perform testing.

from flask import render_templatedef test_firebase_auth_ui(request):    return render_template('test_firebase_auth_ui.html')

Content of templates/test_firebase_auth_ui.html.

  • Make sure test_firebase_auth_ui.html is in templates directory.
  • We shall use Firebase Auth Web/Javascript client with Email/Password authentication for testing.
  • Enable Email/Password Authentication at Firebase Console -> Authentication -> Sign-in method -> Email/Password (Provider).
  • Get firebaseConfig from Firebae Console -> Project Overview -> Add app -> Web.
  • Deploy both test_firebase_auth and test_firebase_auth_ui as cloud functions to perform the testing.
  • Access [SERVER]/test_firebase_auth_ui. Click Create User for first time, then click Sign In buton for subsequent testing. Observe Chrome Console for the messages.
<!doctype html><html lang="en">  <head>    <meta charset="utf-8">    <title>Test Firebase Auth</title>  </head>  <body>    <h1>Test Firebase Auth</h1>    <button id="create-user-button">Create User</button>    <button id="signin-button">Sign In</button>    <script src="https://www.gstatic.com/firebasejs/5.10.0/firebase-app.js"></script>    <script src="https://www.gstatic.com/firebasejs/5.10.0/firebase-auth.js"></script>    <script>      var firebaseConfig = {        apiKey: "AIza...",        authDomain: "[PROJECT_ID].firebaseapp.com",        databaseURL: "https://[PROJECT_ID].firebaseio.com",        projectId: "[PROJECT_ID]",        storageBucket: "[PROJECT_ID].appspot.com",        messagingSenderId: "2401..."      };      firebase.initializeApp(firebaseConfig);      document.addEventListener('DOMContentLoaded', function() {        console.log('init');        var EMAIL = "[email protected]"        var PASSWORD = "test1234"        var TEST_AUTH_URL = '/test_firebase_auth'        var testCloudFunctionAuth = function(credential) {            credential.user.getIdToken().then(function(token) {              var req = new XMLHttpRequest();              req.onreadystatechange = function() {                if (this.readyState == XMLHttpRequest.DONE) {                    if (this.status == 200)                      console.log(`done: ${this.responseText}`);                    else                      console.log(`error: ${this.status}`);                }              }              req.open('GET', TEST_AUTH_URL, true);              req.setRequestHeader('Authorization', 'Bearer ' + token);              req.send();            })        }        var createUserButton = document.getElementById('create-user-button');        createUserButton.addEventListener('click', function() {          console.log('createUserButton.click')          firebase.auth().createUserWithEmailAndPassword(EMAIL, PASSWORD).then(function(credential) {            console.log('create user success');            testCloudFunctionAuth(credential);          }).catch(function(error) {            console.error(`${error.code}: ${error.message}`)          });        });        var signInButton = document.getElementById('signin-button');        signInButton.addEventListener('click', function() {          console.log('signInButton.click')          firebase.auth().signInWithEmailAndPassword(EMAIL, PASSWORD).then(function(credential) {            console.log('signin success');            testCloudFunctionAuth(credential);          }).catch(function(error) {            console.error(`${error.code}: ${error.message}`)          });        });      });    </script>  </body></html>

Wrap Firebase Authentication as Python Decorators

from functools import wrapsfrom flask import abortfrom firebase_admin import authinit_firebase()def firebase_auth_required(f):    @wraps(f)    def wrapper(request):        authorization = request.headers.get('Authorization')        id_token = None        if authorization and authorization.startswith('Bearer '):            id_token = authorization.split('Bearer ')[1]        else:            abort(401)        try:            decoded_token = auth.verify_id_token(id_token)        except Exception as e: # ValueError or auth.AuthError            abort(401)        return f(request, decoded_token)    return wrapper@firebase_auth_requireddef test_firebase_auth(request, decoded_token):    return decoded_token['uid']

NOTE: For init_firebase, refer Initialize firebase-admin.

References:

❤️ Is this article helpful?

Buy me a coffee ☕ or support my work via PayPal to keep this space 🖖 and ad-free.

Do send some 💖 to @d_luaz or share this article.

✨ By Desmond Lua

A dream boy who enjoys making apps, travelling and making youtube videos. Follow me on @d_luaz

👶 Apps I built

Travelopy - discover travel places in Malaysia, Singapore, Taiwan, Japan.