How does realm cloud handle firebase token refresh

cloud

#1

Hi,

Firebase docs says

Firebase Authentication sessions are long lived. Every time a user signs in, the user credentials are sent to the Firebase Authentication backend and exchanged for a Firebase ID token (a JWT) and refresh token. Firebase ID tokens are short lived and last for an hour; the refresh token can be used to retrieve new ID tokens.

I was wondering how to handle this in Android and in Cloud.
I know how to login with JWT, but not sure what will happen once then token is expired.

I’ll update here once I finish my testing, until then if someone can give me a clear guide then it will be of great help.


#2

hello,

I tried login with firebase auth jwt but I don’t see any user (in realm studio user tab) or schema created in realm.

I’m on android

I used SyncCredentials.jwt(String token) method for login purpose.

am I supposed to use it or is there any other method

I have enabled the JWT authentication in
realm cloud settings, added the public key
set the user id key.


#3

@aadi.android What are the logs on ROS and Android?


#4

Hello,

I verified the token I get after signing up in firebase.


#5

@aadi.android You are getting a 403 on the /auth endpoint

If you paste the token into here;

Does it decode?


#6

yes, it does decode.


#7

@aadi.android Can you turn up ROS to debug loglevel and share logs?


#8

how am I supposed to use jwt public key

since firebase uses multiple public keys on rotational basis, I won’t be able to login if token is signed with different public key than the one I provided


#9

@aadi.android That is a good point - we will need to add functionality to programatically update the public key for an instance/tenant. Thanks for pointing that out and sorry for the run-around.


#10

@ianward thank you so much for considering this.
also I wanted to know how does/will realm handle token refresh once it is expired.
will there be any issue if I refresh token manually and again use the jwt/accessToken method in java? such as loss of data pending for sync.

please confirm which method I should use for jwt or share some docs related to this in java.


#11

@aadi.android
the JWT token is only used to authenticate an external user into ROS. Meaning it is used to register/sign in the user and then ROS issues a refresh token based on its own internal tokening system which the client uses to get access tokens per Realm.
Said differently the JWT auth is just used to federate an identity, but once you are authenticated ROS handles everything with its own tokens.

You could manually refresh your JWT token via client-side code and then re-authenticate to ROS.


#12

I am not sure updating the key for an instance/tenant is enough here. To verify the token you need to make sure that

1: Verify that kid corresponds to one of the public keys listed at https://www.googleapis.com/robot/v1/metadata/x509/[email protected]

2: Ensure that the ID token was signed by the private key corresponding to the token’s kid claim. Grab the public key from https://www.googleapis.com/robot/v1/metadata/x509/[email protected] and use a JWT library to verify the signature. Use the value of max-age in the Cache-Control header of the response from that endpoint to know when to refresh the public keys."

reference https://firebase.google.com/docs/auth/admin/verify-id-tokens:

So first you need to grab the KID, and then select which certificate to validate the public key for. Will this use case be supported for JWT authentication? Or do you need to use custom auth (which requires the ROS on premise installation)? I guess another option would be to have a Firebase Cloud Function in between that does the validation and then repackages the key in a format that Realm Cloud would understand and sign it using another public key?


#13

Just tried my own suggestion of connecting Realm Cloud using Firebase Cloud functions. I generated my own public/private keypair and implemented a Firebase Cloud Function to create a JWT based on the uid of the signed in user. The jwt was signed using my private key, the public key was uploaded to realm. Works like a charm!


#14

Great info! Would your Firebase Function solution not work by using the Firebase Auth SDK as mentioned in your link?


#15

Actually, if you use Firebase cloud functions you already get the uid of the signed user by default when you call it from your iOS/Android app. It is probably using the admin SDK under the hood for you, but you don’t have to. The uid is right there in the Context argument that is passed to the Firebase Cloud Function

All you need to do is to create your own jwt using a node package of your choice and add the uid as payload.

If you want to use your own node.js server and the admin sdk, that would probably work just as well, but it is very convenient to use the Firebase cloud functions for this use case.


#16

@Sipe would you mind to share a gist of your Firebase Functions, looks like we are back to the days of configuration.yaml file of ROS developer edition.


#17

Not a full gist, but basically this is what you need to do in your firebase cloud function. Note that you must have generated your own private/public keypair first and uploaded the public key to realm cloud.

const functions = require("firebase-functions");
const jwt = require('jsonwebtoken');
const fs = require('fs');
const key = fs.readFileSync('myPrivateKeyFile');

exports.myAuthFunction = functions.https.onCall((data, context) => {
	const uid = context.auth.uid
	const payload = {
  			userId: uid
  		};
  	const token = jwt.sign(payload, { key:  key, passphrase: "your-passphrase" }, { algorithm: 'RS256'});
  	return {
  		token:token
  	}		
});

For details on how to call this from your app, please see the firebase documentation. https://firebase.google.com/docs/functions/callable

For details on getting started with Firebase cloud functions
https://firebase.google.com/docs/functions/get-started


#18

This looks very interesting, having trouble getting the crypto working, looks I might somehow being an old version of jsonwebtoken because i’m getting:

src/index.ts(26,39): error TS2345: Argument of type '{ key: Buffer; passphrase: string; }' is not assignable to parameter of type 'Secret'.
  Type '{ key: Buffer; passphrase: string; }' is not assignable to type '{ key: string; passphrase: string; }'.
    Types of property 'key' are incompatible.
      Type 'Buffer' is not assignable to type 'string'.