I have an API which uses the node admin sdk to connect and call to firebase. My clients hit my api for all the things they need. I do not want them to have to call out to firebase to authenticate directly because I want the client code decoupled from the api and backend.
How can the server authenticate them? Based on current docs even at minimum clients must provide their uid to the api (which assumes they authenticated on their own, right?).
Ideally, the clients would provide username and password in the body of a POST over ssl to my api and the api would log them in and send back their id token. What would be the recommended way to do this?
If you want to use Firebase for authentication, it is best handled on the client side by a client SDK. This is because authentication is rate-limited based on IP address and it also allows you to skip the process of coding in session management and persistence.
However, you can achieve what you want if you expect a low number of logins/users by hosting the client SDK on your server and hand-balling the request off to Firebase.
// app.js
const bodyParser = require('body-parser');
const cookieParser = require('cookie-parser');
const express = require('express');
const firebase = require('firebase'); // client SDK
firebase.initializeApp({
apiKey: "<API_KEY>",
authDomain: "<PROJECT_ID>.firebaseapp.com"
});
const app = express();
app.use(bodyParser.json());
app.use(cookieParser(['array', 'of', 'secrets']));
// on future requests, the UID can be found using `req.cookies['__session'].uid`
app.post('/login', function (req, res, next) {
if (!req.body.email) return res.status(400).json({error: 'missing email'});
if (!req.body.password) return res.status(400).json({error: 'missing password'});
firebase.auth().setPersistence(firebase.auth.Auth.Persistence.NONE) // don't persist auth session
.then(function() {
return firebase.auth().signInWithEmailAndPassword(req.body.email, req.body.password)
});
.then((user) => { // https://firebase.google.com/docs/reference/js/firebase.User
let uid = user.uid;
// set cookie with UID or some other form of persistence
// such as the Authorization header
res.cookie('__session', { uid: uid }, { signed: true, maxAge: 3600 });
res.set('cache-control', 'max-age=0, private') // may not be needed. Good to have if behind a CDN.
res.send('You have successfully logged in');
return firebase.auth().signOut(); //clears session from memory
})
.catch((err) => {
next(err);
});
});
module.exports = app;
Note: You may also consider co-locating your API using Cloud Functions. Depending on your use case, this may be the cost effective option.