SilentFlow not using CachePlugin in msal-node - javascript

I have implemented msal-node, and are able to fetch tokens and authenticated as expected. I am using the DistributedCachePlugin with my own implementation of ICacheClient and IPartitionManager.
cache: {
cachePlugin: new DistributedCachePlugin(new MsalSessionCacheClient(session), new SessionPartitionManager(session)),
}
When running 'acquireTokenByCode' i see the cacheplugin is used and the data is stored as expected.
If i try to use 'acquireTokenSilent' after the cache has been set i would expect it to read the values from the cache and return the access token or renew with the refreshtoken, instead it fails with error:
SilentRenew Failed: InteractionRequiredAuthError: no_tokens_found: No refresh token found in the cache. Please sign-in.
So my conclution is that it does not use the cache plugin as expected, i have added logging in CacheClient and PartitionManager. Does get triggered during 'acquireTokenByCode', but not during 'acquireTokenSilent'.

Related

How to configure msalv2 js library to renew token on ExpiresOn instead of extExpiresOn?

I'm trying to use msalv2 js library to do SSO authentication. It mostly works but I find an issue with token expiring and how to renew it.
I am calling the aquireTokenRedirect function to get the new token and auto renew it but I see that it keeps returning the same token. I try to auto renew it when my server side code detects that the token is expired. It uses a msal jwt library to check.
My guess as to what is happening is, my app is sending the id token to the server (I use that instead of access token), and the server decodes it and sees the exp value, which is the ExpiresOn value from the msal js response.
When this time has expired, it will return a 401 error which is fine. However then I try to renew it on the client side, but find it gives me back the same token value...
I check the msal response from earlier and notice there is a extExpiresOn value which is a little later in time. So now i'm thinking the msal library only renews on this time.
So the question is, how can I configure msalv2 js library to renew on the ExpiresOn instead of the extExpiresOn?
Thanks
function getTokenRedirect(request) {
/**
* See here for more info on account retrieval:
* https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-common/docs/Accounts.md
*/
request.account = myMSALObj.getAccountByUsername(username);
return myMSALObj.acquireTokenSilent(request)
.catch(error => {
console.warn("silent token acquisition fails. acquiring token using redirect");
if (error instanceof msal.InteractionRequiredAuthError) {
// fallback to interaction when silent call fails
return myMSALObj.acquireTokenRedirect(request);
} else {
console.warn(error);
}
});
}

Firebase HTTPS callable function context.auth is always null when used with custom token auth

HTTPS callable function is called directly from our app after signing in using custom token (custom auth), but context.auth is null in function eventually.
I am wondering if this is something expected? I am not providing any specific example (our client is using Firebase SDK with Kotlin, everything is implemented accordingly to the example in docs), just want to know if maybe someone had similar issue or maybe we need to double check our client's code (custom token authentication is actually working there, since we use firestore with security rules that require it).
I was trying to find some information about certain restrictions, but there's none: Firebase FAQ https://firebase.google.com/support/troubleshooter/functions/auth/callable (nothing about custom token), this answer here Do I need to use verifyIdToken on the context.auth object in firebase cloud functions?
Been asked to add an example of the cloud function, nothing specific, is reproducible with simple one like the following (auth will be always null in log record):
exports.getData = functions.https.onCall((data, context) => {
functions.logger.info('Auth info', { auth: context.auth });
return {
success: true,
data: null,
};
});
Seems like a potential race condition, Ensure that Auth has created the user object before requesting the callable function if you are calling it directly after a sign-in method.
This can be done using a callback from an onAuthStateChanged.
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
// User is signed in.
} else {
// No user is signed in.
}
});
Source: https://firebase.google.com/docs/auth/web/manage-users#get_the_currently_signed-in_user

How to validate JWT token from Google pub/sub push (No pem found for envelope)

Context
I'm following Google's RTDNs guide on enabling Real-Time Developer Notifications. I've successfully created the topic and subscription and have received the push notifications sent to the API that I have created. I would now like to authenticate and validate these messages. For that, I'm following this guide on Authentication and Authorization. Their developer documentation here and here has a seemingly useful example.
The Issue
After following the resources outlined above, I get the following error:
Error: No pem found for envelope: {"typ":"JWT","alg":"HS256"}
Relevant Code
const authClient = new OAuth2Client();
// ...
app.post('/pubsub/authenticated-push', jsonBodyParser, async (req, res) => {
// Verify that the push request originates from Cloud Pub/Sub.
try {
// Get the Cloud Pub/Sub-generated JWT in the "Authorization" header.
const bearer = req.header('Authorization');
const [, token] = bearer.match(/Bearer (.*)/);
// Verify and decode the JWT.
// Note: For high volume push requests, it would save some network
// overhead if you verify the tokens offline by decoding them using
// Google's Public Cert; caching already seen tokens works best when
// a large volume of messages have prompted a single push server to
// handle them, in which case they would all share the same token for
// a limited time window.
// verifyIdToken is failing here with the `No pem found for envelope` error
const ticket = await authClient.verifyIdToken({
idToken: token,
audience: 'example.com',
});
// ...
} catch (e) {
res.status(400).send('Invalid token');
return;
}
res.status(200).send();
});
The Questions
From this, I'm assuming I need to have some public key.
Where do I get said public key?
Where do I put said public key so that the google client is initialized with it?
How can I generate an example JWT to test my endpoint?
Edits
I was able to find the source of this error in their code here:
if (!Object.prototype.hasOwnProperty.call(certs, envelope.kid)) {
// If this is not present, then there's no reason to attempt verification
throw new Error('No pem found for envelope: ' + JSON.stringify(envelope));
}
However, I've verified that the kid attribute does indeed exist in the decoded object:
{"alg":"RS256","kid":"7d680d8c70d44e947133cbd499ebc1a61c3d5abc","typ":"JWT"}
Turns out the kid was invalid and therefore threw the No pem found for envelope error. Once a valid kid was supplied, the error no longer persisted.

Firebase FCM error: 'InvalidRegistration'

I am currently trying to send a PushNotification to a Device Group using FCM with the help of Firebase Cloud Functions but once the notification is sent, it returns with code 200 but with failure :
SUCCESS response= {
multicast_id: 8834986220110966000,
success: 0,
failure: 1,
canonical_ids: 0,
results: [ { error: 'InvalidRegistration' } ]
}
Here is the code I am using to send this notification... what am I missing?
const options = {
method: 'POST',
uri: 'https://fcm.googleapis.com/fcm/send',
headers: {
'Authorization': 'key=' + serverKey,
},
body: {
to: groupId,
data: {
subject: message
},
notification: {
title: title,
body: body,
badge: 1,
},
content_available: true
},
json: true
};
return rqstProm(options)
.then((parsedBody) => {
console.log('SUCCESS response=', parsedBody);
})
.catch((err) => {
console.log('FAILED err=', err);
});
Where JSON values title, body, subject, message are String
In my case, I was sending notifications to topic ("topics/my-topic"). I was missing prepending / in the starting of topic so I was getting the same issue. SO topic should be /topics/my-topic.
May be this helps!!
There is an easier way to send a message to a device group from a Cloud Function. Use admin.messaging().sendToDeviceGroup(). Sample code and instructions are in this guide.
I think your current method is failing because there is something wrong with the group notification key provided in groupId. It should be the string key value that was returned when you created the device group. The error codes are listed in this table. For 200/InvalidRegistration it says:
Check the format of the registration token you pass to the server.
Make sure it matches the registration token the client app receives
from registering with Firebase Notifications. Do not truncate or add
additional characters.
I was losing my mind with this InvalidRegistration error.
Eventually the problem was that I was subscribing my device to "example" but sending the notification json to: "example".
But we actually need to send to "/topics/example"
2 hours of my life wasted..
A registration token is tied to a certain group of senders. When a client app registers for FCM, it must specify which senders are allowed to send messages. You should use one of those sender IDs when sending messages to the client app.
Al you need to do is add a http header 'project_id' with your sender id.
I was getting InvalidRegistration:
Basic meaning: you are using the wrong token. Why? This may happen when you a new registrationToken is given to you in onNewToken (docs), but for some reason you are using the old token. That could happen when:
You're using a different push notification library which remembers token (stores it somewhere locally) and you didn't update that library with the new token.
Your application (or other library dependencies) implements another FirebaseMessagingService, and they conflict. Only one service can accept (react to) to the action sent by the FirebaseMessaging Android library's when a new token is given to it. You can double check this by opening the AndroidManifest.xml in Android Studio and selecting the Merged Manifest tab at the bottom of the tab. You can also place debuggers in each Service from each library you use. You'll see that only one service's onNewToken gets called.
When they conflict, one doesn't get the correct token, and the FCM registration token that gets registered would be wrong. Sending a message to a wrong registration, gets you InvalidRegistration.
for me, it was a mistake that I was passing an Id from my models instead of the tokens of the users
InvalidRegistration simply means that the token is either invalid or expired. You can uninstall the app and then reinstall and get a new token and then try with that token. This will definitely solve your problem.
You can read more here.

Parse user save throws an error without any hint

I'm trying to save an user on the Parse User table using
user.save(null,{
success: function(savedUser){
alert("We saved parseID");
},
error: function(error){
alert('Error'+JSON.stringify(error));
}
})
Unfortunately the error is thrown which contains the object I'm trying to save:
{"username":"ffsdfsd","password":"gdfgfdd","createAt":2016-09-21T13:13:18.965Z", "updatedAt":"2016-09-21T13:13:18.965Z","ACL":{"*":{"read":true},"2FUmrere":{"read":true,"write":true}},"sessionToken":"fdgfdgdgdgdf","objectId":"3ffd3f"}
Any idea? Is it something related to the ACL setting (only read permission)?
if the user that you are trying to save is not the logged in user then this is an ACL issue. When a new user is being created in the database the default ACL is public read but the write permissions are granted only to the user.
If you still want to save new data on this user without changing the default ACL you need to create a cloud code function and in the cloud code function you need to write the following code:
user.save(null,{
sessionToken: request.user.get("sessionToken")
}).then(function(user){
// user saved
},function(error){
// error handling
});
please notice that in my code i sent the logged in user session token (this is required in parse-server) and also i use Promises which is the best practice.

Categories

Resources