#AskFirebase FCM web push token invalidation time - javascript

Do FCM tokens generated using Firebase JS SDK ever expire when user is offline too long?
For example, after calling the following code:
messaging.getToken().then((currentToken) => {
if (currentToken) {
sendTokenToServer(currentToken);
updateUIForPushEnabled(currentToken);
} else {
// Show permission request.
console.log('No Instance ID token available. Request permission to generate one.');
// Show permission UI.
updateUIForPushPermissionRequired();
setTokenSentToServer(false);
}
}).catch((err) => {
console.log('An error occurred while retrieving token. ', err);
showToken('Error retrieving Instance ID token. ', err);
setTokenSentToServer(false);
});
The server has the client token. If the user clears the site data, the client no longer knows of this registration, and no one updates the server that the client is gone. So does it ever invalidates the token? If so, how long does it take to invalidate? I understand that FCM can save messages up to 28 days, so I'm assuming no less than that amount of time?

Tokens might be invalidated for a number of reasons. According to the documentation:
The registration token may change when:
The web app deletes the registration token.
The user clears browser data. In this case, call getToken to retrieve the new token.
The documentation doesn't say anything about expiration times, but your code should be prepared to handle these cases by detecting the change and sending the new token to your backend.

Related

Best way to check jwt token expire status if stored in localstorage

I want to check if the token is expired on client side.
My token is stored in localstorage.
Now what I do is: make a call to the server to check if it is valid but I only do it when the path is: https:exp.com/
code:
useEffect(() => {
verifyToken(auth.token).then((res) => {
if (res.status !== 'success' && res.message === 'Token expired') {
signoutClient(() => {
router.push('/auth/login');
});
}
});
}, [auth.token, router]);
Now the problem here is what if the user goes directly to another url exp : https:exp.com/helloworld
I was thinking to use sockets but I don't know if it could work.
Idea is: client stays in listen, whenever token expires server emits a message.
Any idea on how can I do it?
There are different techniques.
Note that handling time on two different machines (expiration in this case) may lead to issues due to time jitter or clock misalignment, so it is not so straight forward
Passive expiration
My favorite pattern is to have a dedicated server error.
Your server should respond with a particular error when the token is expired (to be distinguished from the 401 Unauthorized due to role access). You then add an HTTP middleware to your client that:
detects this error response
deletes local token and navigates to /auth/login
Or if you have a renew token:
detects this error response
attempts to renew the JWT
repeats the original request on success OR navigates to auth page on failure.
This is a passive system that allows you to treat the JWT as an obscure string and does not have time-related issues.
Return a separate field
If, for security reasons, you want to hide sensible information when the session expires even when the user is not interacting with the UI (like Banking sites do) you need to know when the token will expire. A common technique is to return expiration time together with the token (within the authentication response).
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.JFDV4mOKKh0sMfkBKvsbvm8iWjHEGBXtPvC49ob3qiI",
"expiresAt": 1234567890
}
Or even better
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.JFDV4mOKKh0sMfkBKvsbvm8iWjHEGBXtPvC49ob3qiI",
"expiresIn": 600
}
The first one returns you the UNIX time of token expiration relative to server time. This is subject to time jitter or clock misalignment (this may lead to errors). The second one is better as it lets the UI know within how many seconds (since the Response was received) the token will expire, this can be then used to calculate the UNIX time according to the local clock.
It is common to remove a small time step from expiresAt and expiresIn to avoid clock jitter and clock drift issues.
Parse the JWT
If you have no other solution, you can always parse the JWT:
const JWT = `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjEyMzQ1Njc4OTAsIm5hbWUiOiJKb2huIERvZSIsImlhdCI6MTUxNjIzOTAyMn0.1c_yQjnMZfKUb4UTDE_WvbC71f8xxtyMsdqKKkI1hF8`;
const jwtPayload = JSON.parse(window.atob(JWT.split('.')[1]))
console.log(jwtPayload.exp);
You can use a lib(like jwt_decode) to decode your JWT token, where it's most likely contains an expiration timestamp that you can check(compare it with the current timestamp for this moment) and if it exceeded(expired) just delete it from local storage and redirect user to login page.
But you also have to consider add a catch block for functions which calls your API to check for any 401 response status code to also do the same (in case the token was valid then while the user is moving around its expiry date ends)
If you are using the Axios library, you can use the interceptor to check the token expiration thus you can put in a request that handles the retrieval of a new fresh JWT token from the backend API.

bearer is for the authentication token but is for a different token?

for my MEVN application i am using jwt tokens and i am learning how to send the authentcation tokens via axios. i was told that it is standard practice to put "Bearer " before the token and have the server slice of "Bearer " to read the token's body. but what if i have 2 tokens? the first token is for users, but the 2nd one is for a special account that manages the application. to make life simple i programmed 2 user systems in my application. 1 for regular users and the other for admins. what do i put in front of the admin account token?
example jwt token string that gets passed to server:
Bearer cdsklfj2...
Bearer in Authorization header is simply to tell the server that it's an API token, it has nothing to do with the permission for the user or which user is it.
To distinguish between user roles, you can put roles on your JWT payload. For example, if you decode this token:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjEyMywicm9sZXMiOlsiQURNSU4iLCJOT1JNQUxfVVNFUiJdfQ.u0YXpuJkQ08RBb4_s6yVeGT3Ua21ptUbXvrzopG-txI
you will see that it has userId and roles in the payload, where userId is the user id for that token, and roles are the permission the user has.
So on your express app, you can do something like this:
try {
const payload = verifyToken(jwtToken);
} catch (err) {
// assuming if the verification failed because of invalid token will throw an error
return res.status(401).send(); // Unauthorized
}
// Check from roles array if it has "ADMIN" in it
if ( payload.roles.includes("ADMIN") ) {
adminOnlyFunction(); // Function that can be accessed by admin only
return res.status(200).send();
} else {
// If user has no ADMIN roles, return 403 instead
return res.status(403).send(); // Forbidden
}
But there is a drawback when using this method especially if the JWT token is long lived, let's say userId 1 have ADMIN permission, and before the token expired, you decided that userId 1 is no longer an admin, userId 1 will still be able to call adminOnlyFunction() since the roles information is stored in the JWT payload. You can prevent this by blacklisting the token when you change the user's permission.
I personally wouldn't put roles in the JWT payload, but instead store the user's roles information on your database, and check the roles every time an user sent a request to your server, you can read this answer on why you shouldn't put roles on your JWT, and the better way of doing it. At the end, it will always depends on your use case.

Refresh Firebase Token

I'm using web firebase javascript to authenticate by email and password. This process generates a token which I use to verify on my nodejs backend using firebase-admin. Once this token is generated, I store it on the browser local/session storage.
The front end is AngularJs which I intercept the http request to inject the token stored within the browser.
This is working fine, however after a while this token expire. So what would be the best way to refresh this token before it sends to the nodejs api?
Note: should I requet the currentUser.getToken() every request?
The currentUser.getIdToken() only refreshes the token when the current token has expired! So it doesn't create unneeded traffic or requests to Firebase!
firebase.auth().currentUser.getIdToken(true) // here we force a refresh
.then(function(token) {
// ... do stuff!
}).catch(function(error) {
if (error) throw error
});
You'll see that I added true as an argument to the getIdToken() function. This forces a refresh!
Here is the Firebase Documentation for the getIdToken() function.
I hope that helps!

Token based authorization in nodejs/ExpressJs and Angular(Single Page Application)

In my application,while registering the users i am saving username,password and jwt generated token with these fields in MONGO DB.When user tries to login with correct credentials then i will send the response with stored token.Then at client side(In my controller) i am using the localstorage to store the token so that i can send the same token for each and every request sent by the client.But I found some issues regarding this procedure:
I am generating same token for one user every time.So if any third person is able to get the token then he can access the restricted page.
Am i wasting space in db by storing the generated token in MONGODB
Can Anyone access the token stored in localstorage other than the user.
for each and every request in my single page application,I am again querying mongodb to get the token for that user and validating.Here,I am checking both client side and server side.
I am using jwt to generate tokens,Node,Express,Mongoose in my application
Am i following the good procedure.If not,can you please provide the solution for my approach or any new approach.
I have searched many sites for token based authorization and session based authorization,But nothing worked for me.
Note:I am beginner for Nodejs,AngularjS
You should store token in advanced key-value cache tool like: Redis
That would improve performance remarkably.
You will get token from database for 1st time then it should be stored in Redis. I used to set token as key and username as value. Next request , the token will be given from cache. with Redis you can set expire for token.
When a user registers, you would need to generate a JWT like you're doing now. That's OK. You don't need to save it to the database however. You didn't ask but I assume that the password should not be stored in clear text. You can use something bcrypt to encrypt before saving it to the database.
When user tries to login with correct credentials then i will send the response with stored token
Yes, that's correct way to do.
Then at client side(In my controller) i am using the localstorage to store the token so that i can send the same token for each and every request sent by the client.
Yes, on the client side, you can save the JWT to local storage and send it in subsequent requests to the server.
Now your bullet points:
So that you won't have the same JWT each time, you can include an "exp" claim in the payload (I'm assuming you're using something like jwt-simple to generate a JWT). Something like:
var payload = {
sub: account.username,
exp: moment().add(10, 'days').unix()
};
var token = jwt.encode(payload, "secret");
You don't need to store the JWTs in the database. In some cases, the token issuers (the authorization servers) are not the same as the resource servers. The resource servers only receives the JWTs in a request but there's no way for the resource servers to touch the database used by the authorization servers. Side note: If you eventually need to support refresh tokens, i.e. the JWTs that you hand to the clients will need to eventually expire, then you can store the refresh token in a database. Refresh tokens are not the same as JWTs (access tokens). The complexity to support refresh tokens will increase.
Local storage is not where you store passwords, but it can be used to store JWTs. For that very reason, a JWT must and should expire after a certain time.
Not sure what you mean by saying you check both client side and server side. When the client needs to access a resource (again it's fair to assume that the resource server might not be the same as the authorization server), the only thing that the resource server is passed is the JWT. Anyone can decode a JWT. For example, try to paste your JWT on this site http://jwt.io/. That's why a JWT should not contain any sensitive data. But if the resource server knows the secret that the authorization server uses when it encode the JWT, the resource server can verify the signature. Back to your third bullet, that's why it's OK to store the JWT in local storage of the client.
Update I'm updating this to answer to some of your questions in the comment box.
User clicks on 'Login' button triggers the Angular controller to post a request to the server, something like:
$http.post(url, {
username: $scope.username,
password: $scope.password
}).success(function(res) { ... })
Server receives the POST request, it checks username/password, then it generates a JWT, and sends back to the browser. Note that it does not have to save the JWT to the database. The code would be something like
var payload = {
sub: account.username,
exp: moment().add(10, 'days').unix()
};
var token = jwt.encode(payload, "secret");
res.status(200).json({
token: token
});
Back on the client side, in the success() callback above, now you can save the JWT in local storage:
.success(function(res) { $window.localStorage.setItem('accessJWT', res.token) })
The user is now authenticated. Now when user wants to access a protected resource, user don't have to provide username/password. With the JWT which can be retrieved from local storage, the client can now put the JWT in the Authorization header of the request using the bearer scheme, and sends the request to the server. In code, it would like:
headers.Authorization = 'Bearer ' + token;
The server receives the request. Again, this server receiving this request does not have to be the same as the server which generates the JWT above. The 2 servers can be in 2 different continents. Even if you save the JWT above, that does not do any good to this server which can not access the database where the JWT is stored. But this server can pull out the bearer token from the header of the request, validates the token and carries on with the normal tasks.
Hope this helps.
You do not want to store the JWT in mongoose because it appears in headers when logging in. You first generate a token then hash it using a module like crypto.
There are different ways to do this and they all use Passport which handles the tokens. Here's an example project Satellizer
I would recommend you generate the angular-fullstack project. Then go through the server/auth folder and the client/account folder. You will see how to securely handle authentication in a MEAN based app.

How to have a notification of expired Facebook user access token

I've seen a lot of examples, and read some articles to know well about the access token expiration and it was explained pretty well in this article, Access Token Expiration.
I know how to renew the expiration access token. However, the problem is that, as explained in the article, there are possibly 4 reasons for expiration of access token .
Hence, there is no certainty when the access token will be expired and it can be at anytime. The conventional solution is by using offline_permision which will be deprecated by FB soon.
Here is what I'm trying to achieve:
Once the access token expired, and while when user is using our facebook app, I want FB to notifies me.
Once receiving notification, renew the access token.
I don't think the following achieves what I want.
FB.Event.subscribe('auth.authResponseChange', function(response) {
alert('The status of the session is: ' + response.status);
});
Hence, is there any way to have notification from FB when the access token is expired ?
When you try to access the API with an expired token, Facebook will send back an error message. You just check for that error in your callback function that handles the Facebook response, and if an error exists, refresh the token and try the API call again.
From Facebook:
Facebook doesn't notify you that a previously issued access token has become invalid. Unless you have persisted the expiry time passed to your application along with the access token, often the first your application knows that a given token has become invalid is when you attempt to make a request to the API.

Categories

Resources