Repository: zulip/zulip

Issue:
registration: "Log in with google" with no account takes you to the wrong page for invite-only realms.
To reproduce:
* Create an invite-only realm, foo.zulipdev.com
* Log in to a google account not corresponding to any user in foo.zulipdev.com.
* Go to foo.zulipdev.com and click "Log in with google".
* It takes you to a page that says "You need an invitation to join this organization".

It should instead take you to a page that allows you to log in to the correct google account.
As a V1, it can just give an error like "the google account xxx@domain doesn't have an account in this organization. Please [log in] to the appropriate google account first."

In general I suspect there's something wrong in our logic for invite-only realms here; at no point should you ever get to "You need an invitation to join this organization" from the login page. 


Discussion:
Hello @zulip/server-authentication members, this issue was labeled with the "area: authentication" label, so you may want to check it out!

<!-- areaLabelAddition -->
@zulipbot claim
> In general I suspect there's something wrong in our logic for invite-only realms here; at no point should you ever get to "You need an invitation to join this organization" from the login page.

@rishig I disagree; if you actually don't have an account in the organization, this is exactly the error message you need to receive so that you know how to proceed.

Also, I don't think we need a "new page" as part of implementing this; I think we just want to change the error message text on the login page for this case; by leaving it on the login page, the user can then just click "log in with google" or "log in with github" or whatever at that time.
@timabbott  But why the user is forced to log in again if he doesn't have an invitation. He should be logged in and shall ask for something like 'Request to get invitation' if he wishes. Please let me know if that makes sense to you?
@zulipbot abandon
Well, there are two cases on the user end:
* The user has an account, but it's associated with a different one of the user's Google account (i.e. they clicked the wrong one or actually only have an account associated with their GitHub account).  In that case, they should be put somewhere where they can pick how they want to try to login next.
* The user doesn't have an account, in which case we should let them know they need an invitation from an organization administrator.  It's not clear if we want to offer a "request an invitation" feature; there are spam/abuse issues to think about there.


Ignoring the general point of there being a smell in this flow, what's needed in this specific case is some way to log in to your correct google account. Putting an error on the /login page isn't going to help.

I'm not suggesting a new page. We already have the correct behavior if you're logged in to 0 google accounts, and I'm suggesting we should just copy that behavior.


To address the second bullet, I think we can add a generic statement below the /login box:
"Don't have an account yet? Contact the organization administrator for an invitation."

(no "request an invitation" feature). I can add an issue to add that text, if that seems like a fine solution.
I think we might have something like that already at the bottom of the left side for invite-only realms?
@rishig can you make a hacky screenshot/drawing of what you want things to look like?  What I'd expect is to just get put back on the login screen and make a different choice (if you click "login with google", it lets you pick a different one), or you can do "login with github" if it turns out you don't have a google account.
> we might have something like that already at the bottom of the left side for invite-only realms?

we currently don't

> can you make a hacky screenshot/drawing of what you want things to look like?

If you click "Log in with Google" and aren't signed in to an appropriate google account, I'd want a screen like:

![image](https://user-images.githubusercontent.com/890911/45904488-0de0fb80-bda2-11e8-9acd-b1fa7e0f9e99.png)

I don't think that's possible with Google oauth.  Google's auth API doesn't give us the set of users the user is logged into; instead, we redirect to Google's website, the UI to pick a Google account is on that site, and Google redirects back to us data on just the Google account the user selected.  At no point do we receive the list of options.
I see. ok, in that case I'm fine with the "error message on /login" solution. Something like:
foo@zulip.org doesn't have a account in this Zulip organization. Go to google.com/accounts (or whatever it is) to log into the Google account associated with your Zulip account. 

Opened "put generic text at the bottom of the login box" as #10542. 
ok, I think Zapier is implementing the flow that I want:
![image](https://user-images.githubusercontent.com/890911/45977148-8ee7ff00-bffd-11e8-81a2-af5ea591636d.png)

If the user is signed in to 0 or >= 2 Google accounts, we already do the correct thing.

If the user is signed in to 1 Google account, I think the correct flow is:
* Google will send us the email of the one account they are signed in to.
* If the email of the google account corresponds to a zulip account in that realm, great! Log them in.
* If the email of the google account does not correspond to a zulip account in the realm, show them the dialog box above.






That page is part of Google's site, so not directly under Zapier's control.  If it is, either we already get that behavior (and you're just doing the testing a bit differently between the two, with e.g. Google's cookies remembering your previous selections making the difference; I suspect it's actually this going on), or there must be a setting we can provide that changes the behavior for single-google-account.  In that case, the next step is to figure out where in Google's maze of documentation they discuss this (I just spent 10 minutes looking around https://developers.google.com/identity/protocols/OAuth2, without luck).

In other words, I don't know how to do the "show them the dialog box above" action in your suggestion with Google's OAuth system.
yup, agreed it is likely a one line change in how we talk to Google.

To make the problem more concrete: on the desktop app, I think this means you can't log in at all (via oauth) to two realms using two different google accounts. 
From some more googling:
* https://stackoverflow.com/questions/37711665/forcing-a-user-to-choose-an-account-via-google-oauth2
* https://github.com/discourse/discourse/commit/24d0a7a4c71ba5147a5741c7a19dd061296098a0

So maybe we need to add something like `&prompt=select_account+consent` to the URL we send to Google.  I'm not actually sure what those settings do.  If you want to do some spelunking, see (1) what URL Zapier generates and if it has any of those settings and then (2) try that out in a Zulip development environment (we have docs for setting up Google auth there); patching `params` in `send_oauth_request_to_google`.
Aha!  https://developers.google.com/identity/protocols/OAuth2WebServer#creatingclient has the official documentation for the parameters they support.  
Adding `priority: high` now that a user has actually run into the desktop app problem:
https://chat.zulip.org/#narrow/stream/9-issues/topic/Desktop.20App.20multiple.20Invite.20Only
@zulipbot claim

Resolving patch:
diff --git a/zerver/views/auth.py b/zerver/views/auth.py
--- a/zerver/views/auth.py
+++ b/zerver/views/auth.py
@@ -348,6 +348,7 @@ def send_oauth_request_to_google(request: HttpRequest) -> HttpResponse:
         'redirect_uri': reverse_on_root('zerver.views.auth.finish_google_oauth2'),
         'scope': 'profile email',
         'state': csrf_state,
+        'prompt': 'select_account',
     }
     return redirect(google_uri + urllib.parse.urlencode(params))
 


Test patch: