How can I specify a team to sign in with Slack - omniauth

I'm building a website and I added "Sign in with Slack" button.
I'm using omniauth-slack (latest 8b2371) and it works well.
But I want to allow only the users from my own Slack team.
There is team parameter, but the behavior is not so good (https://api.slack.com/docs/oauth).
It automatically choose the team only if a user is signed in to the team.
Otherwise, the user have to type their team domain manually.
And it gets worse if the user is signed in to another team; it attempts to sign in with the other team although my team id is specified (even, one cannot change/choose the team domain to sign in, there is Authorize button only).
I can disallow the users from other team by checking their team id in the callback action, but I don't want to confuse my team members when they sign in my website with Slack.
Does anyone have the same problem?

Use the workspace's subdomain instead of the Slack default in the authorization URL. In python-social-auth docs this was as simple as defining a new backend, e.g.:
class MyTeamSlackOAuth2(SlackOAuth2):
AUTHORIZATION_URL = 'https://myteamhere.slack.com/oauth/authorize'
And using it instead of the stock one. I don't know what the parallel action would be in omniauth but I will leave that as an exercise for the reader. :)

Related

NextAuth - OAuthAccountNotLinked - Imported data from another website - Autolinking

I have OneLogin setup in my application and is working fine. Am using MongoDB database for storing the sessions, accounts and users.
And now, I imported user data from my old WordPress website(which doesn't uses OneLogin, but the native WordPress login).
So basically I imported the user data from WordPress and populated the users collection using the email_id, name, etc. When I login with the OneLogin into my application, it throws the error saying OAuthAccountNotLinked. When researched I can see that you are not recommending the auto-linking of user accounts for safety reasons. But in my case, it's a OneLogin provider that my client's organization that has now started using. And new OneLogin user registrations are manually approved by the admin. So security wise it won't be a problem. We are only using OneLogin as auth provider!
How can I setup auto-linking in this scenario? Because I have 10,000s of Users in my MongoDB collection(imported from old WordPress website). And each User is being requested to manually register at OneLogin using the same email id they were using before in the old WordPress website and is manually approved within the OneLogin.
Thanks
Quote right from the original site
Automatic account linking on sign in is not secure between arbitrary providers - with the exception of allowing users to sign in via an email addresses as a fallback (as they must verify their email address as part of the flow).
When an email address is associated with an OAuth account it does not necessarily mean that it has been verified as belonging to account holder — how email address verification is handled is not part of the OAuth specification and varies between providers (e.g. some do not verify first, some do verify first, others return metadata indicating the verification status).
With automatic account linking on sign in, this can be exploited by bad actors to hijack accounts by creating an OAuth account associated with the email address of another user.
For this reason it is not secure to automatically link accounts between arbitrary providers on sign in, which is why this feature is generally not provided by authentication service and is not provided by NextAuth.js.
Automatic account linking is seen on some sites, sometimes insecurely. It can be technically possible to do automatic account linking securely if you trust all the providers involved to ensure they have securely verified the email address associated with the account, but requires placing trust (and transferring the risk) to those providers to handle the process securely.
Examples of scenarios where this is secure include with an OAuth provider you control (e.g. that only authorizes users internal to your organization) or with a provider you explicitly trust to have verified the users email address.
Automatic account linking is not a planned feature of NextAuth.js, however there is scope to improve the user experience of account linking and of handling this flow, in a secure way. Typically this involves providing a fallback option to sign in via email, which is already possible (and recommended), but the current implementation of this flow could be improved on.
Providing support for secure account linking and unlinking of additional providers - which can only be done if a user is already signed in already - was originally a feature in v1.x but has not been present since v2.0, is planned to return in a future release.
You probably need to write your own implementation to handle such a situation. And call that implementation on each provider call back. Like a check, the email already exists in DB, through an extra level of verification like OTP etc. Finally, when everything passes, let the user in and store some extra info in the DB for future reference.
Since I wasn't able to find a straight forward solution, I come up with a workaround. It's not a perfect solution, but does the job. Maybe someone else will post a better solution here.
So what I did is, I have all the old user data imported to the users collection in my MongoDB database. And NextAuth uses this users, accounts and session collections to store the User and related data. Btw am storing the session data in database.
In my case, we have sent unique OneLogin registration URLs(created from the OneLogin Admin Dashboard) to our existing users for them to create a new account in OneLogin. Then when the User registers an account at OneLogin, the admin approves/rejects the User. If they are approved, they will be eligible to login to our app using their OneLogin credentials.
What I noticed is that, when a User tries to login, NextAuth checks the email field in users collection to find a matching record. Since we imported the Users from WordPress database, we only have records in users collection and nothing on the accounts collection. In accounts collection, NextAuth is storing the access_token, user_id (mapping to users collection), provider details, etc.
So during login, the NextAuth does the internal checks and finds the existing email in the users collection, but it fails to identify the user as there's no info about the provider(OneLogin) details.
Record from accounts collection:
So what I did is, updated all records in users collection by appending a _TEMP to the email field's values. For example, if there's a record with the value abc#abc.com, it will become abc#abc.com_TEMP
Then what I did is, I wrote an API route(/api/check_old_account) in my NextJS application, where it does the following:
gets the currently logged in User's email id (from NextAuth session)
searches the users collection for the same email id with a "_TEMP" at the end
if there exists a _TEMP version of the currently logged in User, then return a response saying an old account exists
Then in the HOME page, I wrote the code to call the above mentioned api (/api/check_old_account) if the User is logged in. This call is made only once in the HOME page, when everything is loaded. Here the login using OneLogin works without errors because we renamed the existing email id in users collection by appending _TEMP. So when User logins, the users collection inserts a new record with their email and related data to the accounts collection also. Basically there would be two records in users collection for that User now. One is their original email id record that got inserted now when the logged in (eg: abc#abc.com) and their old imported account (eg: abc#abc.com_TEMP). The reason why I wrote the code to call the API in the HOME page only is because, after User logs in, they will be redirected to the HOME page. So thought it won't be necessary to write the code globally or somewhere else.
So, if the above API response says that there's an old account that exists, I display a warning popup to the User saying that there's an old account existing in the database and asks whether they want to link that old account. If the User presses YES button, I make an API call to /api/link_old_account. In this API route, the code is written to perform this:
if there's a _TEMP version email of the currently logged in user in users collection, find the respective record _id that has mappings in the accounts collection.
then change the value of the userId field of that respective record(currently logged in user id) in accounts collection, with the user id of the record with the _TEMP version email.
then delete the record with the _id of the currently logged in user
then update the email field by removing the _TEMP from it
then deletes the records that matches the currently logged in user in the userId field of sessions collection. So that the currently logged in sessions of this User would be invalidated.
then redirects the user back to the HOME page using res.redirect(307, '/')
The solution seems to be working fine so far.

Is there a way to have a 'Google Sign In' button for google accounts that are not signed up with Google Plus?

I'm working on an internal website for the company I work for. The website will be only available to company staff. We use Google Apps for Business, so we would like authentication to be done using our google accounts.
I've gone through 'google sign in' samples from here: https://developers.google.com/+/
It works, but the problem we run into is that it requires the user to sign up to Google+. This is a speed bump we would prefer not to have.
Are there any ways around this? Thanks.
It shouldn't be too hard to roll your own sign in using the lower levels of Oauth, eg 'email' scope. It's hard to give a more specific answer because it depends on your architecture (eg. are you predominantly server-side or client-side) and what kind of session do you want to create by the sign in process. For example, if you are client/REST based, you probably don't want any session at all as REST encourages statelessness. On the other hand, if you are more web based, serving static pages, you will want a session.
In simple terms, you will be doing something that generates an access token, and then processing that access token to determine the email address (or Google ID) of the person who created it. You will then establish some sort of session (eg. using session cookies) that identifies future requests from that user.
Feel free to add some more detail to your architecture and I'll try to finesse the answer.
For simple http servlet sessions, it will be something like.
User requests a protected page
servlet detects that there is no session and/or session has no authenticated user
servlet redirects to an Oauth page to request an access code. something like
https://accounts.google.com/o/oauth2/auth?redirect_uri=xxx&response_type=code&client_id=zz&approval_prompt=auto&scope=email
NB research the exact URL, don't rely on this to be exact
If the user isn't logged on, he'll be prompted; if he has multiple logins, he'll be prompted; if he hasn't yet granted email access, he'll be prompted. If none of these conditions are met (the normal case) he won't see anything.
Browser will redirect to the redirect_uri, carrying an access token (or an auth code if this is the first time the user has used the app)
Post the token to the Google userinfo endpoint, and you will receive a decode containing the email address
Store the email into a session object (or retrieve your own user object and store that)
redirect back to the originally requested page. You can use the OAuth state parameter to pass that around
et voila. all future page requests from that user will be within a session containing some user identification.
NB This is just an outline and I may even have missed a step. You will still need to do your own OAuth research.
Apparently not:
(..) if a Google user who has not upgraded to a Google+ account clicks
on the Sign in with Google+ button, the same consent dialog that opens
will take the user into an account upgrade flow.
Weirdly the docs for OAuth2 states:
Google+ Sign-In works for all users with a Google account, whether or
not they have upgraded to Google+.

Devise: Migrate Google Open ID to Google OAuth

Does anyone have clues about how to do this? I'm basically trying to replace the strategy for "Connect With Google" from OpenID to OAuth. The challenge is identifying an old user (user on Google open ID) when a user signs in under the new OAuth scheme.
I have a working implementation which relies on email address as the primary key, as the open ID strategy captures that. The problem is, I don't want to ask for email in the OAuth flow. The ideal value is simply Google user ID, but the Open ID strategy doesn't seem to capture that.
So I have open ID tokens like https://www.google.com/accounts/o8/id?id=AfSCwGQ4PUaidXSQddJugXKLqU5V0MrXFhJM6UHybPw and trying to understand if I could get a Google ID from that.
UPDATE: I explained here how I ended up doing this migration - http://softwareas.com/migrating-user-accounts-from-google-openid-to-google-oauth-to-google-plus
We don't have a strategy ready today that avoids the user seeing another approval page.
However, rather than attempt to do an OAuth1 based hybrid flow and have to add all that legacy code to your server, I'd suggest you simply correlate on email address and move to OAuth2 login. I'm assuming you're like the majority of sites that end up asking for email address because they usually want it for account recovery. Just make sure you get the email address from OpenId as one of the signed parameters.
Then use the userinfo.email scope and OAuth2 https://developers.google.com/accounts/docs/OAuth2Login and you should be able to migrate with less developer pain.
In addition, we're in the process of adding support for OpenIDConnect and it supports a parameter of login_hint so you'd add &login_hint=bob#gmail.com to your authorization URL and it will steer the approval to the right account. This is not documented right now but it may be useful for you to try it. The user's browser could be logged into Google with a number of accounts and you want to try to get the right one. Always check the email you get from the OAuth2 flow to make sure it matches since this is just a 'hint'.
Users will still have to re-authorize for OAuth2, but we have plans to skip this reauthorization in the future. The main point is to plan on using OAuth2 and we hope to deliver a seamless migration soon and you'll be on a supported protocol.
Google uses directed identifiers for OpenID that are unique per relying party and are explicitly designed to conceal any correlatable identifier for the user. So the short answer is, no there's no way to get a Google ID that corresponds with a given Google OpenID.
One option, however, might be to use Google's OpenID+OAuth Hybrid flow. This allows you to get an OAuth token as part of a normal OpenID flow, which could then be used to get the user's ID from the OAuth2 Login API, which you can then associate with their existing account. Once you've done that for all of your existing users, then switch to using the OAuth2 Login directly.
The trick, of course, with this approach is getting all of your users to login again so that you can send them through the new flow. That will come down to how long you're willing to wait to migrate accounts, and whether you're willing to prod existing users by emailing them and asking them to login again (similar to a forced password reset).

How does one build a facebook app as a Company user (rather than a personal app)?

I'm building a Facebook app for a client who have a Facebook company page and I'm stumped as to how to develop the app so that they can actually have access to it without binding it with my own personal FB Login (to which I obviously have no desire to grant them access).
They have added me as an admin to their FB page but when I'm logged into that and go to developer.facebook.com I'm told that to proceed I have to switch back to my own personal account.
I'm sure I'm missing something fundamental here, but am totally confused as to what the process is to build an app for a third party, so that they don't have to give me their personal FB login and I don't have to give them my own.
TIA.
You should create and manage Facebook apps using your real, personal accounts.
You can add multiple, real users to be administrators of an app, and you can add them under several different "roles". You should never give another person the username and password to login to your personal Facebook account.
You should not setup a new Facebook user in order to manage apps. When Facebook's automated systems detect a non-real user account, and that account is suspended, all apps that account is connected with will also be affected.
If you want an easy way to control many users having access to many apps, you can create a secret Facebook group - add all the users who you want to admin the app to the group, then in the Facebook app dashboard, you can add that group to one of the app's role groups. This method has the advantage that, if someone joins or leaves the company, you just have to add/remove them from this group, and they'll then be able to edit (or not) all the apps to which that group has been added.
In short - always use your real accounts - there are ways to make it work for people like you building apps for clients.
You will want to use the Roles settings of the FB app to add Admins (and optionally Developers, Testers, and Insight Users). Each app can have multiple admins. When you create the app you'll be an admin, of course. Then, go to the Roles tab in your app's settings and add others as admins (note, you must be FB friends with them). The people you have added must then visit the Developers site, accept the admin request (under Apps), and will then have admin privileges.
Another way is create a FB group whose members are admins of the app. This is done the same way, but instead of typing a person's name, click "Create a group for administrators" in the "Add Administrators" dialog. Then, add people to the group.
In fact, any of your existing FB groups can be added as an admin, developer, tester, or insight user of the app.
Yet another option is to have the client create the FB app initially (ie. just the minimum config), and then add you as an admin.
More on Roles:
https://developers.facebook.com/docs/ApplicationSecurity/

Advise needed for multiple signin methods in a web application

I'm looking for some strategic advise on the implementation of an application that supports multiple signin methods.
In fact I already have most of it working. In my application, I allow users to sign up and sign in using the classic approach: an account managed by me, where I offer all the user management features, such as sign in, sign out, sign up, email activation, password reset, password change, edit email address, etc.
However, users can also sign up and sign in using their Twitter account. The system will let the user authenticate at Twitter and authorize my application access to their account, then Twitter redirects to my application and I am given the Twitter user name. Currently, if that user name is not known to me, I create it in my database. If it is known to me, yet it is a different account type (a native account), I throw an error.
Basically, currently users have to choose a signin method at account creation and stick to it. There are two ways I can see to improve the situation:
Allow for multiple signin methods
Users would have one account, but multiple ways of signin in. Let's say a user has a native account named "joedirt", associated with email address "joe#dirt.com". Next, this user does not sign in using the native method, yet chooses the Twitter way. At Twitter he is called "joedirt" as well.
The problem here is that from Twitter I only get his username. It would be a major security leak if by name matching alone I could sign in to a native account.
What am I to do here? Ask the user that signs in with an additional method for his email address? It would be the only way to be sure that this concerns the same user, right?
Allow for one signin method only, yet the ability to choose one at any time
An alternative approach could be to let the user only use one signin method at a time, yet the option to set this as a preference and change it even after the account is created. Two scenarios could unfold:
From native signin method to 3rd party signin method. Since I cannot get the email address from the 3rd party signin, how will I ever link the native account to a 3rd party account? Again, username matching is too weak, right?
From 3rd party signin method to the native method. An unlikely event, should I even support this?
Sorry for the long story. I'm having a bit of a mental block on what the best approach is and what the consequences for each scenario are.
How about letting the user "link" her account to other sign-in methods when she is already signed in? That way, it wouldn't be a problem if the third-party provider only supplies limited information (such as the Twitter username).
Either way, I suggest you generate an unique native ID for each user instead of throwing errors when native usernames collide with third-party dito. Think of the user and her sign-in methods as different (but related) concepts.