Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Firebase authentication with custom token

I have a firebase project which Im trying to authenticate from my rails server creating a custom token with the library ruby-jwt as it says on the docs, but i keep getting the same error:

auth/invalid-custom-token, The custom token format is incorrect. Please check the documentation.

The credentials.json is from the service account I made in google console, uid is sent from the front end to the api.

def generate_auth_token(uid)
  now_seconds = Time.now.to_i
  credentials = JSON.parse(File.read("credentials.json"))
  private_key = OpenSSL::PKey::RSA.new credentials["private_key"]
  payload = {
      :iss => credentials["client_email"],
      :sub => credentials["client_email"],
      :aud => 'https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit',
      :iat => now_seconds,
      :exp => now_seconds+(60*60), # Maximum expiration time is one hour
      :uid => uid.to_s,
      :claims => {:premium_account => true}
    }
  JWT.encode(payload, private_key, 'RS256')
end

it looks like this in jwt.io

{
  "iss": "[email protected]",
  "sub": "[email protected]",
  "aud": "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit",
  "iat": 1486824545,
  "exp": 1486828145,
  "uid": "4",
  "claims": {
     "premium_account": true
   }
}
like image 643
Porfirio Diaz Avatar asked Feb 14 '17 23:02

Porfirio Diaz


People also ask

How do you get custom tokens on Firebase?

To achieve this, you must create a server endpoint that accepts sign-in credentials—such as a username and password—and, if the credentials are valid, returns a custom JWT. The custom JWT returned from your server can then be used by a client device to authenticate with Firebase (iOS+, Android, web).

What is custom token authentication?

What Are Custom Authentication Tokens? An authentication token is some data, represented as a string or XML, that identifies an entity (user or process), such as an X509 client certificate. Typically, authentication tokens are designed to be used within specific security protocols.

How do I use token in Firebase?

The access tokens can be generated using a service account with proper permissions to your Realtime Database. Clicking the Generate New Private Key button at the bottom of the Service Accounts section of the Firebase console allows you to easily generate a new service account key file if you do not have one already.


1 Answers

It looks like the accepted answer found a way to link authentication from Firebase to Rails, but the original question seems to be asking how to link Rails authentication to Firebase (which is what I was trying to do).

To keep your authentication logic in Rails (ex: from Devise) and share it with Firebase, first get a Firebase server key as a .json file from your Service Accounts page in your project's settings.

You'll only need the private_key and client_id from this file, which I recommend storing as environment variables so they're not potentially leaked in source code.

Next, make a Plain ol' Ruby object (PORO) that will take in a User and spit out a JSON Web Token (JWT) that Firebase can understand:

class FirebaseToken
  def self.create_from_user(user)
    service_account_email = ENV["FIREBASE_CLIENT_EMAIL"]
    private_key = OpenSSL::PKey::RSA.new ENV["FIREBASE_PRIVATE_KEY"]

    claims = {
      isCool: "oh yeah"
    }

    now_seconds = Time.now.to_i
    payload = {
      iss: service_account_email,
      sub: service_account_email,
      aud: "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit",
      iat: now_seconds,
      exp: now_seconds + (60*60), # Maximum expiration time is one hour
      uid: user.id,
      # a hash to pass to the client as JSON
      claims: claims
    }
    JWT.encode payload, private_key, "RS256"
  end
end

Now send this JWT to authenticated users through javascript in your application layout:

window.firebaseJWT = "#{FirebaseToken.create_from_user(current_user)}";

In your frontend code, you can now use this token to authenticate users:

firebase
  .auth()
  .signInWithCustomToken(window.firebaseJWT)
  .catch(error => {
    console.error(error);
  });

Remember to sign them out of firebase when they sign out of your application:

firebase
  .auth()
  .signOut()
  .then(() => {
    // Sign-out successful.
  })
  .catch(error => {
    console.error(error);
  });
like image 152
cgenco Avatar answered Oct 12 '22 12:10

cgenco