wolverine239
wolverine239

Reputation: 265

How to pass Firebase Auth Token from client to server?

The website that I'm working on uses Firebase authentication and different users that login have different permissions as to which pages they can visit.

The way signing in is setup is similar to this post:

  1. User Logins in with two parameters - "id" and "email"
  2. Server uses these to create a custom "uid", then uses the Firebase Admin SDK to create a custom token that is sent back to the client.
  3. The client logs in with the Javascript Firebase SDK - firebase.auth().signInWithCustomToken()
  4. Now that the user is logged in, they can click different pages - i.e. '/foo', '/bar'

The issue I'm running into is that when they visit new pages, I'm trying to pass the token from the client back to the server (almost identical to how its done in this Firebase Doc ), verify the token & check if it has permission to view the webpage.

I'm trying to figure out the best (& most secure) way to do this. I've considered the following option:

I've been trying to pass the token in the request header, but from my understanding you can't add headers when the user clicks on a link to a different page (or if its redirected in javascript). The same issue applies to using POST.

What can I do to securely pass this information to the server and check permissions when a user clicks on a link to a different page?

Upvotes: 21

Views: 11191

Answers (2)

Jordan Warbelow-Feldstein
Jordan Warbelow-Feldstein

Reputation: 10748

Nowadays, it looks like we're meant to use httpsCallable() client-side to get an object pre-authorized to talk to your endpoint.

eg:

// # ./functions/index.js
exports.yourFunc = functions.https.onCall((data, context) => {
  // Checking that the user is authenticated.
  if (!context.auth) {
    // Throwing an HttpsError so that the client gets the error details.
    throw new functions.https.HttpsError('failed-precondition', 'The function must be called ' +
      'while authenticated.');
  }
  // ... rest of your method
});
// ./src/models/addMessage.js
const firebase = require("firebase");
require("firebase/functions");

firebase.initializeApp({
  apiKey: '### FIREBASE API KEY ###',
  authDomain: '### FIREBASE AUTH DOMAIN ###',
  projectId: '### CLOUD FUNCTIONS PROJECT ID ###'
  databaseURL: 'https://### YOUR DATABASE NAME ###.firebaseio.com',
});
var functions = firebase.functions();

// This is the new code:
var yourFunc = firebase.functions().httpsCallable('yourFunc');
yourFunc({foo: bar}).then(function(result) {
  // ...
});


From firebase documentation

Upvotes: 0

mehyaa
mehyaa

Reputation: 3411

You can get the accessToken (idToken) on client side by:

var accessToken = null;

firebase.auth().currentUser
    .getIdToken()
    .then(function (token) {
        accessToken = token;
    });

and pass it in your request headers:

request.headers['Authorization'] = 'Bearer ' + accessToken;

and on your server side get the token with your prefered method and authenticate the request with Firebase Admin SDK, like (Node.js):

firebaseAdmin.auth()
    .verifyIdToken(accessToken)
    .then(decodedIdToken => {
        return firebaseAdmin.auth().getUser(decodedIdToken.uid);
    })
    .then(user => {
        // Do whatever you want with the user.
    });

Upvotes: 28

Related Questions