Managing SSO Discord Sessions - authentication

I'm working on an application that uses discord SSO to authenticate users via the authorization grant code flow. Currently, I have the sign in flowing working as expected and I fetch my users guild (server) information to be able to build authorization based on their roles, but I am having trouble with managing users sessions.
My goal is to be able to have users sign in once through SSO and maintain their session without requiring them to go through the SSO flow when the session expires. Currently, once a user signs in I create or update their account by storing basic user information as well as the access token and refresh token from the provider. Then, when the session I created for them expires I can check the users access token and refresh token stored in the database to refresh the user credentials in the background without sending them through the SSO flow unless the tokens expired or failed to refresh due to a token being revoked from a password changed or something.
Does anyone have any tips or resources on best practices for integrating with SSO and maintaining user sessions? Any tips or feedback is appreciated!
Note: I know it is weird that my account system is based on discord server because a user can be constantly changing with changes to roles, name, ect.... I have a background service subscribed to these events storing them in a queue to be processed so that my account stay 1:1 with the guild.

Related

Persisting a login with the Slack API

I currently have this flow but I am unsure of the architecture going forward.
On my page, the user gets sent to the Slack OAuth API where they confirm scopes
User gets redirected back to my page with a one time code
Client sends a request to the server with the code
The server sends a request to Slack with the code, exchanging it for an access token
If the code and token are OK, it creates a new user in MongoDB
I made a flowchart to illustrate:
I would like the user to not have to authorize the scopes every time they want to access the service, and even if they did, how would I keep the token around in a secure manner to make requests? Would I have to create my own token authentication with login and password, or is there a better way? Should I persist this token on the client somehow and have the users be logged in that way? If so, what is the best way to do that?
Slack token generation must be one time activity per user.
When creating user in MongoDB, you should also store the generated token securely.
For later use, your application should use the stored token for any slack interactions, given that you have authenticated the user whose token you'll be using.

How to use Google Identity to log in from multiple devices?

How can I use Google Identity platform as a login / registration system for my own service?
Specifically - how can I do this and support login for same user from different devices?
Using for web service, nodejs without npm modules: passportjs / googleapis / google-auth-library.
My idea:
User opens myClientApp/login page and clicks on GoogleLogIn button which will ask him to authorize my service for specific scopes of his Google account.
I then get the refresh token & access token and save it in DB, then send the refresh token to the client with cookie.
Whenever I make a call to my own service API I send the refresh token from the cookie.
As long as I have valid access token saved in my DB or the refresh token is not expired - I treat the user matching that refresh token as an active session for my service.
Security problems:
cookies attacks, and the refresh token is easily accessed from the browser. Could use https / encryption and more methods to secure the cookie and it's value. Still- someone could copy the cookie from one computer to another!
Multiple login problems:
If the user login on different device, a new refresh token will be created. The previous device the user logged in to will now hold a wrong refresh token in the cookie...
Could the OpenID solve this? Do I need to use JWT?
What is the most secure way to use Google Identity login in my own service while supporting multiple devices login for the same user?
First, make sure that you really understand the security implications for what you want to do.
For example, NEVER send the Refresh Token to a client.
If you want to use the same tokens for the same client on multiple devices, you have a chicken and egg situation. How do you "authenticate" the user at each device. How do you know that user "John" is actually user "John" but on a different device the first time?
Your goal is not to trade convenience for less security. Your goal should always be security first, no matter the inconvenience.
A better approach is to let Google authenticate and authorize a user on each device. They only have to do this once per device. Your backend systems keep track of the Refresh Token issued for each device. You can then generate the Access Tokens and Identity Tokens when needed - they expire after one hour anyways. Store a cookie on the user's device that identifies them to your system so that you can look up who they are, get the Refresh Token, create new Access Tokens, etc.
There is a limit to the number of Refresh Tokens that can be issued before the oldest ones are voided. I think the number is 50. This is usually not a problem. If a Refresh Token is invalid, just put the user back thru the authenticate process and store the new token.
Also provide the user with a sign-out method that removes all stored tokens in your system.
The cookie that you store on the client's devices should be opaque meaning that there is no stored information in the cookie and the cookie is only valid for that device and no other devices. This solves the stolen cookie moved to another device problem.
I will now touch on some of your questions:
My idea: User opens myClientApp/login page and clicks on GoogleLogIn
button which will ask him to authorize my service for specific scopes
of his Google account.
Google OAuth does not work that way. You send the user to a URL, Google manages all display and input with the end user. Once everything is complete a callback URL on your server is called and you are passed a code. The exact details depend on the type of OAuth Flow that you are using.
I then get the refresh token & access token and save it in DB, then
send the refresh token to the client with cookie.
During the OAuth Flow you will request the Access Token, Refresh Token and Identity Token. The Refresh Token is saved in the database. Never send this token to the client. Read my suggestion above about creating an opaque cookie that you send to the client.
Security problems: cookies attacks, and the refresh token is easily
accessed from the browser. Could use https / encryption and more
methods to secure the cookie and it's value. Still- someone could copy
the cookie from one computer to another!
Create an opaque cookie that is only valid for that device and no other devices. If a client sends you a cookie intended for a different device, consider this a problem and invalidate all cookies, tokens, etc for this user on all devices.
Multiple login problems: If the user login on different device, a new
refresh token will be created. The previous device the user logged in
to will now hold a wrong refresh token in the cookie...
I covered this issue above. Store the Refresh Token generated for each device in your DB. Consider each device / Refresh Token / cookie as a set.
Could the OpenID solve this? Do I need to use JWT? What is the most
secure way to use Google Identity login in my own service while
supporting multiple devices login for the same user?
By Open ID I think you mean Open ID Connect (OIDC). This is already integrated into Google OAuth and this is the part that generates the Identity Token.
Do I need to use JWT?
Google OAuth Tokens are generated from Signed JWTs. However for the most part you do not need to worry about the format of tokens. Google provides endpoints that validate and decode Google OAuth tokens.
What is the most secure way to use Google Identity login in my own
service while supporting multiple devices login for the same user?
I covered this question in the first part of my answer above.

How do I keep the user logged-in with Implicit flow?

From what I understand, the end-result of the implicit flow is the access token, which allows the client (in my case a JS SPA) to authenticate into resource servers (APIs).
The access token is usually only valid for ~1 hour, then it expires - making it useless.
What should my JS app do then? Redirecting the user back to the auth server is unrealistic since then the user will have to reenter their credentials every 1 hour!
I also know that the implicit flow doesn't support refresh tokens so I can't use those either.
Is there a way to persist the user's login? How do things like Facebook keep you logged-in indefinitely?
Just to clarify, you are asking about the Implicit flow which is detailed in the OAuth 2.0 RFC rather than OpenID Connect which deals more with authentication of a user?
With the implicit flow you do have to regularly call the authorisation endpoint to obtain a new token, but if the user remains logged into their identity provider then they should not be prompted to resubmit their credentials, and the token will be returned as a hash fragment in the redirect uri, with no user interaction required.
You can use an AJAX call to get the token on a back-channel so your SPA app user experience is not affected by the need to get new tokens.
To address the points you highlight in your question:
The access token is usually only valid for ~1 hour, then it expires -
making it useless.
Correct!
then the user will have to reenter their credentials every 1 hour!
Not necessarily.
If the user stays logged into the identity provider (e.g. facebook, google) then there will be a browser cookie between the user and that provider. This effectively means the identity provider does not need the user to re-enter credentials. The authorisation server should be able to return you a token with no interaction required.
Is there a way to persist the user's login?
You can't control it from your SPA. It's totally dependent on the user staying logged onto the identity provider. If they stay logged into facebook, google (or whatever IDP you app uses) then you should be able to get tokens non-interactively.
This article nicely explains how the implicit flow can be implemented.
If the session at the OP is still active (via a cookie perhaps), then OpenID Connect has a mechanism to refresh tokens in a (hidden) iframe: prompt=none.
According to the spec, when sending this flow...
The Authorization Server MUST NOT display any authentication or consent user interface pages. An error is returned if an End-User is not already authenticated or the Client does not have pre-configured consent for the requested Claims or does not fulfill other conditions for processing the request. The error code will typically be login_required, interaction_required, or another code defined in Section 3.1.2.6. This can be used as a method to check for existing authentication and/or consent.
prompt=none is also referred to from the Session Management specification.

SSO & Existing OAuth integrations

Good Evening,
My group is rolling out SSO - yay. We have several applications that directly authenticate with Box.com and all token refreshes are handled automatically. After we migrated to SSO, we didn't include these service (app) accounts in our AD, so they do not have access via the SSO gateway.
My (likely incorrect) understanding of how OAuth with an SSO provider in the loop works:
We can still start the OAuth handshake directly with box - but box will forward this request to the SSO provider. The SSO provider will then authenticate the credentials and pass back a "all good" to box, which will issue an auth_token.
This is based off of the following from box:
"If you authenticate your application via Box’s OAuth 2.0, your
application will automatically let the customer sign-on with their
company credentials, just like they do with every other Box
application. This also applies to popular commercial services like
Okta, One Login, and Ping."
https://docs.box.com/docs/oauth-20
As well as this photo:
So if the external applications' service accounts with Box aren't in the AD of the SSO (too many acronyms), they should not be able to authenticate right?
But these apps are continuing to be able to authenticate. They are able to refresh their token and continue accessing box, even after the migration to SSO.
Where is the flaw in my understanding? Will these apps need to be added to the AD, or does this roll out of SSO not affect any of our external dependencies?
Thanks!
Got an answer from box:
third-party apps and integrations use a persistent authentication
token model. This means that unless a user deliberately logs them out
of the app, or an admin inactivates or deletes their account, this
user will never have to re-authenticate after initial login. Instead,
the app/integration will refresh their tokens. Refreshing tokens does
not require stepping through the SSO login flow, while generating an
initial set of tokens does.
Changes in SSO status, whether between SSO Off, Enabled, and Required,
or between two different connections, have no effect on existing
authentication sessions. Users won't be forcibly logged out when SSO
is turned on.
Upon next login attempt will the new SSO flow come into play. In this case, these users were already authenticated into the integration
prior to SSO roll-out. The SSO change would have impacted behavior in
that these users would need to authenticate via SSO going forward;
however, due to the persistent authentication model, that "next login"
never actually happens, and these users can continue to refresh tokens
and retain access without ever being challenged to authenticate into
the IdP again.

How to update claims or logout a user immediately when changes made on IdentityServer?

The problem I've experienced with claims based solutions in web apps so far is that if, on the SSO server, I revoke claims or delete the user account, the user's token is still in their cookies and is therefor still valid until the token expires, allowing them to continue to access the web app. Is there a way to force update a user's token or force revoke a token (or just check back with the identity server every time the user tries to load a page?) as soon as a change is made on the server? The same goes for updating claims... sometimes we add rights. It's very annoying to users to have to logout and log back in. Please help. We're using C# Web Apps and Thinktecture IdentityServerv3
You can use refresh tokens and a smaller auth token lifetime to force the client to come back regularly. It isn't immediate revocation, but it is a simple method you can use to cut down the period between server revocation and client change.
Refresh tokens