Truly Authul

Greyboi
The Infinite Machine
13 min readJan 27, 2018

Making a minimal Python App Engine app that implements Firebase Authentication

In this previous article, I said I had a new year’s resolution to stop dealing directly with user authentication, and wrote about using Firebase and App Engine together.

In this article, I develop a minimal app in Python on App Engine (using Flask on the back end) that implements Firebase Authentication.

Here’s the architecture I’ll be using.

It’s a simplified version of the Cat Dog As A Service architecture from the previous article, in which we’re just doing authentication.

1 — The Client will authenticate via Firebase Authentication.

2 — It’ll then have an authentication token to use when talking to App Engine.

In this article, the app I build will simply allow logging in and out via Firebase. Then in the next article/app, we’ll get to talking to backend APIs, checking the Firebase auth, and acting accordingly.

1: Start with a skeleton app

A while back I made a skeleton app for Flask based applications. Here’s the repo:

Here’s the article about it:

So I’ve copied that into my trulyauthul1 project.

Let’s run it to remember what it does:

How’d I run it?

  • I ran scripts/setup.sh to get the python libraries using pip
  • I ran it locally using scripts/runlocal.sh

Ok, nice. How’s that work?

I’ve got src/app.yaml that says

runtime: python27
api_version: 1
threadsafe: true
automatic_scaling:
max_idle_instances: 2
handlers:
- url: /static
static_dir: static
- url: /.*
script: main.app

That last bit tells me to look for src/main.py; it looks like this:

import logging
from flask import Flask
app = Flask(__name__)from handlers.helloworld import get_helloworld
get_helloworld(app)
@app.errorhandler(500)
def server_error(e):
# Log the error and stacktrace.
logging.exception('An error occurred during a request.')
return 'An internal error occurred.', 500

Ok, we’ve got a helloworld handler being registered with Flask, in src/handlers/helloworld. And that looks like:

from flask import render_templatedef get_helloworld(app):
@app.route('/', methods=["GET", "POST"])
def helloworld():
return render_template("helloworld.html")

We’re rendering a helloworld.html template. I see one in src/templates, but how’s it finding that? Oh, here in the Flask doc:

Right, so helloworld.html is a jinja2 template, and it’s in the relative templates folder. Hmm, that’s more magic than I’d implement, but ok Flask people, cool.

Finally, here’s src/templates/helloworld.html:

<html>
<head>
<title>Hello World!</title>
<link rel="stylesheet" type="text/css" href="static/main.css">
</head>
<body>
<h1>Hello World!</h1>
</body>
</html>

Revolutionary stuff.

2: Let’s change it to “Truly Authul”

Ok, so I want to demonstrate Firebase Authentication. OTOH, I’m a very lazy man. What to do?

As little as possible sounds good.

Ok, so let’s change the Hello World handler to say “Truly Authul”. Also, let’s include the user’s name or email address or whatever we can get hold of.

Update main.py:

from handlers.trulyauthul import get_trulyauthulget_trulyauthul(app)

Now we need src/handlers/trulyauthul.py:

from flask import render_template#, request, redirectdef get_trulyauthul(app):
@app.route('/', methods=["GET", "POST"])
def trulyauthul():
return render_template("trulyauthul.html")

and src/templates/trulyauthul.html:

<html>
<head>
<title>Truly Authul!</title>
<link rel="stylesheet" type="text/css" href="static/main.css">
</head>
<body>
<h1>Hello there whatsisname, welcome to Truly Authul!</h1>
</body>
</html>

Ok, let’s run it!

Good, good.

3: Let’s add Firebase Authentication

So what I want to do now is require the user to authenticate before they get to see an internal Truly Authul message.

So far, the web page is rendered in the back end. But Firebase Authentication really wants to work in a SPA (Single Page App).

So, what’s the laziest path to getting that going?

Let’s just stick with the trulyauthul.html template, but we’re going to javascript it up, and firebase it up. It’ll check if you’re authenticated, and either force you to authenticate, or show you the welcome message if you are authenticated.

What Javascript framework will I use? Vanilla

Having a look at the Firebase Authentication docs, the Firebase UI approach looks satisfyingly lazy; check it out:

Can be customised to fit my visual style? I guess they do Times New Roman on white then.

<clicks Web>

I’ve ended up at this Github repo:

Oh, the Readme is legit. Let’s go through step by step.

CDN means no libraries to include or anything like that. Easy, let’s do that, just include those lines… oh, but “below the initialization snippet from Firebase Console.” Hmm.

Well, in fact we’ve jumped ahead a bit.

4: Setting up the Cat Dog as a Service (App Engine + Firebase project)

To use Firebase, we’re going to have to stop trying to develop locally (boo!) and get set up online. I need to create an App Engine project, tie it to a Firebase project, and then in the Firebase console I’ll find the sneaky snippet.

So I head over to Google Cloud Platform, and create a new project:

Wow, 476 projects remaining? Last I remember with App Engine, I was limited to 10 or 15 or something. Great!

Ok, now let’s pop over to Firebase and create a project there.

Create that project! It also asked me for a billing plan, Blaze is right (just pay as you go). Now you’ll see the main console page. Choose “Add Firebase to your web app”…

Note Firebase is very much about Mobile too, you could do apps here.

… and you get this.

That’s the initialization snippet from the Firebase Console!

Note these conflicting messages:

Okay, ima put it at the top and let’s see how we do. Here’s src/templates/trulyauthul.htmlnow:

<html>
<head>
<title>Truly Authul!</title>
<link rel="stylesheet" type="text/css" href="static/main.css">
<script src="https://www.gstatic.com/firebasejs/4.9.0/firebase.js"></script>
<script>
// Initialize Firebase
var config = {
apiKey: "AIzaSyDTd_xbonBWasEIdlczX-J6v3OlQ8TWtBA",
authDomain: "trulyauthul.firebaseapp.com",
databaseURL: "https://trulyauthul.firebaseio.com",
projectId: "trulyauthul",
storageBucket: "trulyauthul.appspot.com",
messagingSenderId: "526098954239"
};
firebase.initializeApp(config);
</script>
<script src="https://cdn.firebase.com/libs/firebaseui/2.5.1/firebaseui.js">
</script>
<link type="text/css" rel="stylesheet" href="https://cdn.firebase.com/libs/firebaseui/2.5.1/firebaseui.css" />
</head>
<body>
<h1>Hello there whatsisname, welcome to Truly Authul!</h1>
</body>
</html>

Alright, that’s supposed to be how we set up Firebase and Firebase UI. Now let’s deploy it and run it online and see what happens.

I need to edit scripts/deploy.sh to fix the app engine deploy for this project. Note we don’t need to deploy anything to Firebase. Here’s scripts/deploy.sh:

cd ../src
gcloud app deploy app.yaml --project <<yourprojectname>> --version defaultversion --verbosity=info

Run this, whirr whirr whirr, and success! Let’s go take a look:

Nothing really interesting happening here. OTOH, we shouldn’t have expected much; Firebase is set up, but we’re not actually invoking it. For that, we need to go back to the Firebase UI git repo Readme.

5: Hooking up Firebase UI so it does something

Let’s head back to the Readme. Next bit:

Um, I already began thanks.

Right, that looks like a bit of a PITA. Let’s just pick one, and we can expand it later. I’m forever using Google for authentication, so let’s mix it up and do Facebook. Click, we get this:

I’ve done step 1. Step 2 says we head off to Facebook for Developers, and register Truly Authul as a Facebook App.

Facebook for Developers? I haven’t been there since Zynga was a thing. Click…

that’s just waaaaaay too much pressure.

You know, I guess this is global scale, isn’t it? It’s the intarwebs, and you’re maybe in some other country than I am.

Okay! Fired up! Let’s do this Facebook, let’s go global! Now to register my app and get an App ID and an App Secret…

Let’s Monetize our Verticals and Build Out 10X Growth! Because those things are real!

I can’t even. Maybe Google can help. In fact, she can, she gives me this link:

which includes the following list:

That looks like a huge awful chore, we’re on the right track. My plan is to do as little as possible here, then throw a smoke bomb and disappear.

Logging in to Facebook is itself almost a deal breaker; I hate doing that. But ok.

Creating a developer account just threw errors and failed a lot, but now I see I already am one.

(if in doubt, go to developers.facebook.com and monetize something)

Create new Facebook app (this is on developers.facebook.com):

gets me this

And this seems like a win:

There’s the App ID, and the App Secret is under Settings in the menu. Got it.

Smell you later, Zuck!

Edit: I vanished too quickly. It turned out only I could use the facebook login; I had to publish the facebook app to make it available to others. That’s a straightforward thing you do in the facebook developer’s console.

Ok, back to Firebase’s instructions for setting up Facebook login, we’re up to step 3:

That’s 3 more steps! Those trickers!

Ok, here we go in the console, adding the App ID and App Secret:

Apparently I have to set up an OAuth Redirect in my Facebook app configuration. Oh, this:

But what’s the taters, ey? How do I do this?

It turns out lots of other people struggled with these taters. Here’s an answer on Stack Overflow:

So I think it’s this:

#obviouslynotobvious

Alright, does that work? No idea yet. Let’s hope so.

So where are we up to now?

6: Hooking up Firebase UI so it does something (5 turned out to be about Facebook nonsense)

So there are more, very Facebooky instructions about how to deal with auth below the “before you begin” bit, but let’s ignore those (!) and go back to the Facebook UI readme.

Following their example, I get this:

<html>
<head>
<title>Truly Authul!</title>
<link rel="stylesheet" type="text/css" href="static/main.css">
<script src="https://www.gstatic.com/firebasejs/4.9.0/firebase.js"></script>
<script>
// Initialize Firebase
var config = {
apiKey: "AIzaSyDTd_xbonBWasEIdlczX-J6v3OlQ8TWtBA",
authDomain: "trulyauthul.firebaseapp.com",
databaseURL: "https://trulyauthul.firebaseio.com",
projectId: "trulyauthul",
storageBucket: "trulyauthul.appspot.com",
messagingSenderId: "526098954239"
};
firebase.initializeApp(config);
</script>
<script src="https://cdn.firebase.com/libs/firebaseui/2.5.1/firebaseui.js">
</script>
<link type="text/css" rel="stylesheet" href="https://cdn.firebase.com/libs/firebaseui/2.5.1/firebaseui.css" />
<script type="text/javascript">
// FirebaseUI config.
var uiConfig = {
signInSuccessUrl: '/',
signInOptions: [
// Leave the lines as is for the providers you want to offer your users.
// firebase.auth.GoogleAuthProvider.PROVIDER_ID,
firebase.auth.FacebookAuthProvider.PROVIDER_ID,
// firebase.auth.TwitterAuthProvider.PROVIDER_ID,
// firebase.auth.GithubAuthProvider.PROVIDER_ID,
// firebase.auth.EmailAuthProvider.PROVIDER_ID,
// firebase.auth.PhoneAuthProvider.PROVIDER_ID
],
// Terms of service url.
tosUrl: 'https://goo.gl/Fbui2b'
};
// Initialize the FirebaseUI Widget using Firebase.
var ui = new firebaseui.auth.AuthUI(firebase.auth());
// The start method will wait until the DOM is loaded.
ui.start('#firebaseui-auth-container', uiConfig);
</script>
</head>
<body>
<h1>Hello there whatsisname, welcome to Truly Authul!</h1>
<div id="firebaseui-auth-container"></div>
</body>
</html>

Okay… what’s that going to do? It looks like Firebase UI is being constructed, then rendering itself into the firebaseui-auth-container div.

Deploying again, I refresh http://trulyauthul.appspot.com/ and I get:

Ooh, it seems like the firebase UI is putting that sign in button there! Let’s click it!

“This domain (trulyauthul.appspot.com) is not authorized to run this operation. Add it to the OAuth redirect domains list in the Firebase console -> Auth section -> Sign in method tab.”

Ok. Something like this?

Add, then refresh http://trulyauthul.appspot.com/ and try clicking again.

Now some action! I get this:

I Click “Continue as Emlyn”, and get redirected back:

Oh.

Well, I guess I don’t actually do anything in my javascript when a log in succeeds, or even check if I’m logged in, or anything like that. You’d think that might be important.

7: Let’s wire this thing up so we know if the user is authenticated

This seems like a lot of steps so far. I thought it would be easier.

This is why they pay me the big bucks.

There’s another sample in the readme which says to put an onStateChanged handler on the Firebase auth service, to track when a user logs in or out, so you can do things like showing details about the logged in user, providing a signout button, etc.

The code they provide is a bit odd, and it’s not clear how it combines with Firebase UI, but I’ll throw in the handler.

Now what I’ve already noticed is that the Firebase UI piece seems completely oblivious to whether you’re already logged in. So, I’ll change things so it’s only displayed if we’re not already logged in. Easy enough.

But what about if we are logged in, how do we sign out? Glad you asked.

It doesn’t say anything about this in the sample code, but what Firebase UI is achieving is to get us signed in, in a standard Firebase way. This means the whole of the Firebase SDK is available to us. Long story short, we should sign out in whatever way is standard for Firebase.

We need to look at a Firebase sdk service called auth, which is about all about authentication.

It turns out there’s a method called signOut() on the auth service, ie:

firebase.auth().signOut()

will do the job.

So given all this, here’s a working version of src/templates/trulyauthul.html:

<html>
<head>
<title>Truly Authul!</title>
<link rel="stylesheet" type="text/css" href="static/main.css">
<script src="https://www.gstatic.com/firebasejs/4.9.0/firebase.js"></script>
<script>
// Initialize Firebase
var config =
{
apiKey: "AIzaSyDTd_xbonBWasEIdlczX-J6v3OlQ8TWtBA",
authDomain: "trulyauthul.firebaseapp.com",
databaseURL: "https://trulyauthul.firebaseio.com",
projectId: "trulyauthul",
storageBucket: "trulyauthul.appspot.com",
messagingSenderId: "526098954239"
};
firebase.initializeApp(config);
</script>
<script src="https://cdn.firebase.com/libs/firebaseui/2.5.1/firebaseui.js">
</script>
<link type="text/css" rel="stylesheet" href="https://cdn.firebase.com/libs/firebaseui/2.5.1/firebaseui.css" />
<script type="text/javascript">
// FirebaseUI config.
var uiConfig = {
signInSuccessUrl: '/',
signInOptions: [
// Leave the lines as is for the providers you want to offer your users.
// firebase.auth.GoogleAuthProvider.PROVIDER_ID,
firebase.auth.FacebookAuthProvider.PROVIDER_ID,
// firebase.auth.TwitterAuthProvider.PROVIDER_ID,
// firebase.auth.GithubAuthProvider.PROVIDER_ID,
// firebase.auth.EmailAuthProvider.PROVIDER_ID,
// firebase.auth.PhoneAuthProvider.PROVIDER_ID
],
// Terms of service url.
tosUrl: 'https://goo.gl/Fbui2b'
};
// Initialize the FirebaseUI Widget using Firebase.
var ui = new firebaseui.auth.AuthUI(firebase.auth());
initApp = function() {
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
// User is signed in.
var displayName = user.displayName;
var email = user.email;
var emailVerified = user.emailVerified;
var photoURL = user.photoURL;
var uid = user.uid;
var phoneNumber = user.phoneNumber;
var providerData = user.providerData;
user.getIdToken().then(function(accessToken) {
document.getElementById('sign-in-status').textContent = 'Hi ' + user.displayName + ", welcome to Truly Authul!";
document.getElementById('sign-out').style.display = 'block';
document.getElementById('firebaseui-auth-container').style.display = 'none';
document.getElementById('sign-out').textContent = 'Sign out';
document.getElementById('sign-out').onclick = function(event){
firebase.auth().signOut();
};

console.log("account details: " + JSON.stringify({
displayName: displayName,
email: email,
emailVerified: emailVerified,
phoneNumber: phoneNumber,
photoURL: photoURL,
uid: uid,
accessToken: accessToken,
providerData: providerData
}, null, 2));
});
} else {
// User is signed out.
document.getElementById('sign-in-status').textContent = 'Hello there! Please sign in to access Truly Authul';
document.getElementById('sign-out').style.display = 'none';
document.getElementById('firebaseui-auth-container').style.display = 'block';
ui.start('#firebaseui-auth-container', uiConfig);
}
}, function(error) {
console.log(error);
});
};

window.addEventListener('load', function() {
initApp()
});
</script>
</head>
<body>
<div id="sign-in-status"></div>
<button id="sign-out"></button>
<div id="firebaseui-auth-container"></div>
</body>
</html>

Let’s see what this does. Deploy, refresh, and…

Ok, let’s click it…

Let’s click Sign out:

That’s success!

Closing Thoughts

So we did it, we got basic Firebase authentication working!

You can try it here:

And you can see the code here:

That didn’t seem easy, but you get a lot out of being authenticated with Firebase, which hopefully I’ll get to demonstrate in later articles.

In the next post, I’ll change Truly Authul so it talks to a backend API in App Engine, that API checks the user, and returns something different depending on whether we are authed or not.

Thanks for reading!

--

--

Greyboi
The Infinite Machine

I make things out of bits. Great and terrible things, tiny bits.