firebase / firebase-js-sdk

Firebase Javascript SDK
https://firebase.google.com/docs/web/setup
Other
4.86k stars 895 forks source link

How to use refresh token? #497

Open wapgear opened 6 years ago

wapgear commented 6 years ago

I'm using

firebase.auth().signInWithCustomToken(this.props.sessionToken)

for login with custom session token, but I also want to use the refresh token to have user still auth after 1 hr (default time of expiring).

How can I use https://developers.google.com/identity/toolkit/reference/securetoken/rest/v1/token with firebase-js-sdk?

google-oss-bot commented 6 years ago

Hey there! I couldn't figure out what this issue is about, so I've labeled it for a human to triage. Hang tight.

google-oss-bot commented 6 years ago

Hmmm this issue does not seem to follow the issue template. Make sure you provide all the required information.

bojeil-google commented 6 years ago

Please provide more context. What is this sessionToken? Is it a custom token? Please do not pass around refreshToken especially if you plan to use this as a way to bypass the idToken short lifetime which is meant for security purposes.

tfpereira commented 6 years ago

I'm suffering from the same problem and I currently have no way of keeping "permanent" auth on users. After generating a JWT token on my API and passing it to the client, I'm capable of signing in with the method @wapgear describes above.

However, after the 1 hour exp time passes on the jwt token, AngularFireAuth.authState starts returning null.

I've read through documentation but I can't seem find a way to refresh the token and keep the user logged, since I lose the reference and I can't execute .getToken(true) in order to refresh the token.

Is there some detail I am missing in regards to how custom tokens work?

bojeil-google commented 6 years ago

Signing in with a custom token should create an indefinite session (returns a new refresh token which should be persisted locally). I don't know why you are getting null after one hour. I am not familiar with the angularfire library and would recommend you file a bug with the owners to investigate.

vincentwoo commented 6 years ago

So, oauth is kind of a huge pain in the ass. You can see how we handle this in the Ruby SDK: https://github.com/oscardelben/firebase-ruby/commit/85a5145d558287b8ca301fdb1db5d373fc462904.

TLDR: you need to ask for a new dynamic token every hour, which you can do with your static credentials.

tfpereira commented 6 years ago

I think I might have found the culprit for the problem with the session dissappearing after the exp time on the JWT playload. I was doing some testing yesterday, and the problem might have been with the API restrictions I had in place for the API key I'm using on my mobile client.

On Google Cloud Platform API Keys management, I only had "Identity Toolkit API" in the whitelist of scopes my API Key could use. However after adding "Token Service API" to the whitelisted scopes suddenly my app has been able to keep authentication for the last 24 hours without a problem.

So the problem most likely was lack of permissions when it came time to refresh the token and not a code problem per se.

leolux commented 6 years ago

@bojeil-google the infinite session only works on a single origin because the firebase SDK uses the IndexDB for the local persistence. On a different origin, i.e. on a different subdomain the IndexDB might be empty and therefore the firebase SDK fails to auto-signin. The customToken doesn't help because it is expired after 1 hour. How to auto-sigin after 1 hour on a different origin controlled by the same backend able to generate customTokens without forcing the user to input the credentials again?

leolux commented 6 years ago

@tfpereira what does Google Cloud Platform API Keys management have todo with firebase?

tfpereira commented 6 years ago

If my memory doesn't fail me, the API key that my mobile client uses to connect to firebase is managed on GCP.

On Thu, 19 Apr 2018, 09:38 leolux, notifications@github.com wrote:

@tfpereira https://github.com/tfpereira what does Google Cloud Platform API Keys management have todo with firebase?

— You are receiving this because you were mentioned.

Reply to this email directly, view it on GitHub https://github.com/firebase/firebase-js-sdk/issues/497#issuecomment-382656612, or mute the thread https://github.com/notifications/unsubscribe-auth/AKtRP4EKqIjHflYTgMsGsrQXAjoBnx8dks5tqE0igaJpZM4R-IZK .

bojeil-google commented 6 years ago

You pass the custom token, sign in with it on the other domain and then you have 2 sessions. You don't store the custom token.

blairbodnar commented 6 years ago

Thanks for the info @bojeil-google

FYI after some digging I found the docs that describe it in detail here: https://firebase.google.com/docs/auth/web/auth-state-persistence

Taivas commented 6 years ago

Just stuck into the same problem, I was trying to figure out how to refresh token since it seems to expire in an hour. But doc Create Custom Tokens part explains for the 'exp'

The time, in seconds since the UNIX epoch, at which the token expires. It can be a maximum of 3600 seconds later than the iat. Note: this only controls the time when the custom token itself expires. But once you sign a user in using signInWithCustomToken(), they will remain signed in into the device until their session is invalidated or the user signs out.

Here 'session is invalidated' means the user is deleted or disabled, so it will keep the valid sign-in state if you do not log out, delete or disable the user.

abdel-ships-it commented 5 years ago

I need an answer to this question as well. Everybody seems to give the advice you should let the SDK do the work of maintaining your session. Most of the time you should, but in my case I am using the SDK in node.js. And it seems it does not persist the refresh token and id token after logging in with a custom token, I think in node.js this is actually not supported.

https://github.com/firebase/firebase-js-sdk/blob/89ead882d110cd1521148288c5fe275a5a965941/packages/auth/src/authstorage.js#L107

I have created a firebase support ticket on the firebase website, but I am not really getting the answers I am looking for.

lux-capacitor commented 4 years ago

Yeah I see the same thing currently:

  1. I am using a Python API to create a FS token for the client side with the admin SDK.
  2. Pass that token to client side and it uses it via auth().signInWithCustomToken(token), which works great.
  3. After a while, bout an hour, I end up getting issues with the /verifyCustomToken call that the Client-Side SDK does failing due to the token being "Invalid" according to the response.

So, the question is, HOW do you use the refresh_token that comes back from the step #2 I outline above, to keep the token alive each hour? do I just use the refresh token again with auth.signInWithCustomToken( REFRESH_TOKEN HERE ) ?

malcolmdeck commented 4 years ago

Hey Lux, fair question.

The Firebase SDK doesn't have any APIs that interact with the refresh token directly, so if you want to use the refresh token you'll need to use the Firebase Auth REST API. You should check out the section Exchange a refresh token for an ID token.

On a related note, you're getting an Invalid error because your custom token has expired - if you don't want to have to use the REST API, you can mint a new custom token and call auth().signInWithCustomToken(customToken) if you want the SDK to handle this for you.

nathan-ca commented 4 years ago

Hi @malcolmdeck,

I used the REST API you mentioned and got the following response:


{
  "access_token": "eyJh...",
  "expires_in": "3600",
  "token_type": "Bearer",
  "refresh_token": "AG8B...",
  "id_token": "eyJh...",
  "user_id": "A0CP...",
  "project_id": "3349..."
}

However, how to use returned data to sign in again? I tried firebase.auth().signInWithCustomToken() method with 3 tokens in the response data but all failed. I couldn't find any other method I can use to authenticate the node.js client again.

nathan-ca commented 4 years ago

@Abhishek12345679 The correct way is to send id_token back to sever end and verify the token. Check this out: https://developers.google.com/identity/sign-in/web/backend-auth

developerJuiceLozzoc commented 4 years ago

A series of http requests. if you want PURE SERVERLESS you'll have to pay for cloud functions.. for example if you have a native android or iOS app, you need a server. you use the http rest api with your Web API key and your refreshToken you get from user.refreshToken to get a id or access token, which you jsonwebtoken decrypt it to get the user id, and create a custom token let uid = 'some-uid';

POST https://securetoken.googleapis.com/v1/token?key=[web API key]
BODY
```{
    "grant_type": "refresh_token",
    "refresh_token": "AG8B..."
}

{ "access_token": "eyJ...", "expires_in": "3600", "token_type": "Bearer", "refresh_token": "AG8B...", "id_token": "eyJhbGc...", "user_id": "Mm...", "project_id": "69..." } / WITHOUT A SERVER https://stackoverflow.com/questions/38233687/how-to-use-the-firebase-refreshtoken-to-reauthenticate however I couldn't get this to work./ let customToken = await requestP.post({ headers: {'content-type': 'text/plain'}, url: 'https://.cloudfunctions.net/createCustomToken', body: {token: res.access_token}, json: true });

/ WITH A SERVER Then you use the access_token or the user_id or the id_token to jsonwebtoken to get the userid/ admin.auth().createCustomToken(uid) .then(function(customToken) { // Send token back to client }) .catch(function(error) { console.log('Error creating custom token:', error); });



and pass that back to the client application to `Auth.auth().signIn(withCustomToken: <#T##String#>, completion: <#T##((AuthDataResult?, Error?) -> Void)` 
Ceraz-CV commented 1 year ago

I've had the exact same problem and actually found the reason for this.

My auth workflow is based on https://gourav.io/blog/firebase-auth-chrome-extension: A web app with a logged in user gets a custom token from the backend and passes it to the web extension. The extension then uses the token to auth. This only works for one hour.

The reason for this is the call of "initAuth()" whenever the extension is opened/initialized. Firebase is not done figuring out the auth state so authClient.currentUser == null. Since it looks like no user is logged in this triggers the call of signInWithCustomToken() with the now (after one hour) expired custom token. This overrides the actually present current user with it's refresh token that just hasn't got the time to be used by firebase. Since the ID-token and the custom token have the same expiration time it looks like firebase did not refresh the ID-token but actually this refreshing is intervened by the call of signInWithCustomToken() with an old custom token.

Simple Solution: Let firebase figure out the authentication when reloading the script. Instead work with onAuthStateChanged() if you need to intervene in any way to make sure firebase is in the correct state. This fixed the issue for me.