I am writing an oauth2/OpenID connect integration for a private project.
The requirement is that the customer retains full control of their users via their own systems, and that I allow SSO login in my Meteor application. The customer must be able to lock out the users as well as changing some attributes, which eventually must be caught my Meteor app as well.
I used accounts-base, accounts-oauth and facebook-oauth as a template, and with some trials and errors I have been able to login via a user that exists on a development Keycloak instance. Hurray .
Next, I invalidated the session on Keycloak, but my user is still connected. That is reasonable, since I have a one-hour access token. However, I noticed that the access token is never refreshed, its expireAt, while saved in user profile, does not seem to do anything and therefore the user is never logged out.
I could set up the Meteor login session validity to the time of the access token, but that would also make the application almost unusable since the user would need to login once per hour. Actually, I expected the accounts-oauth, accounts-base or some other packages to try and refresh the access token, and lock out the user if the operation can not be completed, but that does not seem what the current implementation do.
I can fix this by writing my own server custom logic (run every X minutes, check for expired access token, try refresh and log-out the user if that is not valid), but I was curious to know if anyone here had the same issue, as to me it seems like a common requirement with SSO.
Thanks to anyone who took their time for reading this post and has some comments.
If I misunderstood the whole SSO mechanism or if I am missing something obvious please feel free to criticize me
Ok, what I understand…
You want something LIKE SSO. I don’t think you can do SSO.
Let’s say a user exists and is authenticated in a CustomerSystem. Then the user wants to access your Meteor system.
I am trying to understand the UX here …
- Let’s say you Iframe your Meteor into the CustomerSystem page. The user clicks on a link from the CustomerSystem interface. The iframe opens (or stays hidden from the screen and things … run). On completion, you direct to an authenticated Meteor session in another window.
- the user goes directly to your Meteor page and expects to have an option to login with CustomerSystem credentials?
Which one is it? 1 or 2 or both or something else?!
It is exactly option number 2. Sorry for my bad explanation
ok the way I would do it …
There used to be a Meteor package called Restivus. I don’t know if any recent version is being maintained but what I would do is to make a call from CustomerServer to my Meteor server to create a user when a user is being created, to update when … the required attributes are updated and to invalidate/delete, mark for deletion a user when this happens on the CustomerServer.
Basically, servers talk to each other.
Then when I log-in in Meteor, I would definitely go for Passwordless. If a user exists, and it is valid, give me a password on my “corporate” registered email. Then I log in.
Meteor.userId() can be reactive on the client and you cam make use of it to make sure you kick out the session in Meteor if a user no longer exists. You can also disable the user creation from the client side allowing only your CustomerServer to create/update/delete user data.
Also user updates and user state updates are independent from user’s activity, they only depend on servers talking to each other.
Thanks a lot for your opinion!
I will definitively have a look at Restivus, which is interesting for many reasons.
However, that seems to overcomplicate the current solution, which is mostly working.
My current implementation (which is just a modified version of facebook-oauth and google-oauth packages, btw) “works”, I just need to logout users eventually and check their attributes once in a while.
I could easily make a timer running on the backend that checks for expired oauth access token every X minutes, tries to refresh them and logs out users if the refreshtoken fails.
This is unpleasant, as problems arises for multi-instances (I will have race conditions for sure), but I expect it to work nevertheless.
My actual issues are:
- I do not understand why this is not considered “SSO”, in fact to me it seems to be exactly the definition of federated SSO;
- I expect login via Facebook/Google/other social providers to be a common usecase in meteor apps (given the abundance of pre-made packages); has anyone not considered that revoking access via the credential provider should block the user login in the third party app? This seems like a security issue to me.
Ok, from the security and privacy point of view, if a user leaves a system (inactivated), she has to leave all systems at the same time. If you need user attributes right as they change across systems, you cannot rely on cron jobs. I would not do it that way because there is too much risk for data inconsistency. A user attribute may include roles and access details for secondary systems. If I want to downgrade a user I expect the user to be downgraded everywhere.
I understand that your context might not be subjected to very strict standards and that you are ok to rely on cron/scheduled jobs.
“Single sign-on is an authentication scheme that allows a user to log in with a single ID to any of several related, yet independent, software systems. True single sign-on allows the user to log in once and access services without re-entering authentication factors.”
Ok, this consideration is interesting.
For this particular application, I expect that the customer will be fine if the log-out conditions will be checked at each access token expiration. Also, the customer will be free to change the access token duration to a shorter value, so that at most an expired user can use the system for a limited amount of time.
Moreover, I can:
- create an API endpoint with Restivus for immediate user logoff (which the customer will be in charge to call, eventually);
- force an access token refresh for major actions, such as data deletion;
I do not expect that the customer will go as far as implementing an API call to forcefully log out a user, but surely they will be happy for this possibility.
As a side note, the users are currently managed via a CSV that they send us once per week, which we semi-manually process to create new users and delete blocked users. Even the change to a “create immediately, block at most after an hour, no manual edits for us to do” will be a huge improvement for the customer, so honestly I am happy as-is.