Performing Google Federated Login/oAuth2 after initial Authentication - oauth

I am trying to support "Hybrid" Federated Login and oAuth2 (using logic from this document) for a webservice which will:
support Sign in using your Google account on my site. That is, from the documentation: You can also choose to use Google's authentication system as a way to outsource user authentication for your application. This can remove the need to create, maintain, and secure a username and password store.
Access the user's Google Analytics.
Here are the steps I have done.
I form my request to https://accounts.google.com/o/oauth2/auth with the scopes (Google Analytics) I want access to.
I Get redirected to google where it has my icon and which scopes I am requesting access to. I grant access.
I get redirected back to the callback page.
I get the tokens (access and refresh), as well as a huge id_token string (which I don't know) and store all of this information in my database.
I then make a call to https://www.googleapis.com/oauth2/v1/userinfo?access_token=xxxyyyzzz to get the user's email and name and store this information in my database too. I also notice it returns a id field which to my knowledge never changes and I presume is some sort of unique identifier. I store this too.
Question: If I go to Authorized Access to your Google Account section in my Google account, it shows that my site has access to "Google Analytics. BUT, it does not say Sign in using your Google account. This is what I am trying to accomplish. I would have thought using the logic would enable Sign in using your Google account. What am I doing wrong? And what would be the applicable call to google so that users can sign in to my site?

If your site has access to something like your Contacts or Analytics using OAuth, you'll never see "Sign in using your Google account". I'm pretty sure that's only if you use OpenID (not OAuth) only for sign-in.
Specifically, OAuth is used for giving you access to APIs to create/update/delete data, while OpenID is for signing in.

If you are asking how to identify user for future logins, you have two options:
Mix OAuth with OpenID, that is called Hybrid. I have described it on this answer.
Use userinfo scope and request userinfo (email, etc.) after successful OAuth authorization. It is described on Google OAuth 2 documentation.
If you mean automatically login to your web site in future visits you can use OpenID "immediate mode" (openid.mode parameter).

When the user is redirected back, you call the second request from your own (server-side?) code, and get their email address. When you successfully get it, that means that the user is logged on. You can add it to the session (e.g. as cookie), and as long as you have it, the user is logged on. You make the user log out by forgetting the email address, so by clearing the session/cookies.

Add this paramter to the https://accounts.google.com/o/oauth2/auth URL call: approval_prompt=force and then the Sign in using your Google account will always show regardless of whether the user was already signed into that or any other account.
So the call would be like this https://accounts.google.com/o/oauth2/auth?client_id=<client id>&redirect_uri=<uri>&scope=<scope>&access_type=<online or offline>&response_type=code&approval_prompt=force

Related

Who is auth server in OAuth2.0 between two Apps eg. between Google and Twitter

I know that OAuth2.0 is framework using to authorization data request between apps, but to give this access auth server is required. It is my question: who is this server? Let's say: We have two apps: Twitter and Google. I am trying to register Twitter account using Google account. And now where is this auth server? Is it Google? Or maybe it is another third server (managed by Twitter and Google together where user data is?) If it is Google, how Twitter is able to check if user token (generated by auth server [Google??]) is valid?
Thanks
On your first question,
I am trying to register Twitter account using Google account. And now
where is this auth server? Is it Google?
Yes, it's Google. If you're trying to login/register to Twitter via Google, Google is the authorization server. Because, Google has to authorize/delegate access to Twitter to access your data such as your Gmail id, username, etc.
Once you click on "Sign up with Google" button on the Twitter registration page, you will be redirected to the Google login page first (to see if you're an authenticated google user) and then Google would show you a consent page saying that "Twitter is trying to read your profile data, are you okay with this?". Once you click on "Allow" button, Google will generate an access_token, id_token, and refresh_token and pass it to Twitter.
On your second question,
If it is Google, how Twitter is able to check if user token (generated
by auth server [Google??]) is valid?
Twitter is not going to validate the tokens. Twitter can pass the token to retrieve your Google profile information from Google's Resource Server (where all your data reside)
Google's Resource Server is the one that's going to validate the token. It first checks the 'iss' claim of the token to see if the token is issued by Google's Authorization Server. Additionally, it would check for 'aud' to see if the token is issued for them (recipient of the token). Finally, it checks for the 'scope' claim to see if Twitter has the right access to request the data. For eg, they would need to request only read-only access to your profile, but not write access. There could be additional validation depending on the use case.
I hope this answers your questions.

Rleationship between Google Identity Services - Sign In with Google and User Authorization for Google APIs

I'm studying the Google document on "Google Identity Services" and seem to see two stories. One is called "Sign in With Google" which presents an attractive button where a user can sign-in with their Google account. The other is the Google Identity Services Authorization which grants an access token to make API calls.
What I am missing is whether or not there is a relationship between these two concepts/SDKs/functions. My mind is saying that I want a pretty button on my web page that I can use to sign in (ala Sign in With Google) AND I want the click of that button to give me an access token that I can use to invoke Google APIs. What I seem to be finding is that they are separate and discrete concepts with no obvious relationship between them. Is that correct?
References
Google Identity Services JavaScript SDK - Authorization
Sign in with Google
2022-06-26: Following a post from Blunt, I tried to add a hint but that didn't seem to make a difference. Here is the code I have been using. First, the index.html that loads the test:
<!DOCTYPE html>
<html>
<body>
<script src="https://accounts.google.com/gsi/client"></script>
<script src="./index.js"></script>
<div id="g_id_onload" data-client_id="XXX.apps.googleusercontent.com"
data-callback="handleToken" data-auto_prompt="false">
</div>
<div class="g_id_signin" data-type="standard" data-size="large" data-theme="outline" data-text="sign_in_with"
data-shape="rectangular" data-logo_alignment="left">
</div>
</body>
</html>
and the JavaScript loaded in index.js
const clientId = "XXX.apps.googleusercontent.com"
function handleToken(x) {
debugger;
const client = google.accounts.oauth2.initTokenClient({
client_id: clientId,
hint: "myemailaddress",
scope: 'https://www.googleapis.com/auth/calendar.readonly',
callback: (response) => {
debugger;
},
});
client.requestAccessToken();
}
What I am finding is that I get a the button in the web page as desired ... I click the button, I am prompted to sign in to Google and then the debugger statement (the first one) in the handleToken function is reached. The code progresses and then I am prompted to sign in to Google a second time. It had been my hope that the first sign-in would have been sufficient and somehow context would be preserved for the authorization.
In the new Google Identity Service, the authentication (sign-in) and authorization (access to api's) are separated, but not entirely distinct.
I have an article that explains this, and a reference implementation for pure client-side solution. npm install gothic will get you that reference implementation.
But here are the details:
(1) The sign-in with Google gives you the pretty button. Signing in provides user information encoded in a JWT. But none of this provides an access token.
(2) To obtain the authorization, you need to drive a second, sequential process. To expedite this process you can use the email address from the sign in process as an optional hint parameter to the authorization library, but the first time the user accesses it, they will still need to go through an explicit authorization process, depending on what api's (scopes) you need to access.
With regard to authorization, there are two models:
(1) Token-based. This is the pure client-side version. With this, you ultimately provide your clientId, your API-key, the discovery uri and the scopes to the library, and you get back a 1-hour token, that authorizes use of the APIs your app needs. As I mentioned, this requires an explicit prompt to the user the first time, and is click-free thereafter. But you will need to renew that token every hour, or on each page refresh.
(2) Code-based. This requires you to have a server-side to your app as well. In this model, your client obtains a code from Google, and hands that to your server. Your server exchanges it for an access token and a refresh token, and thereafter uses the refresh token to obtain new access tokens.
The server-side, code-based model is the more secure, and can ultimately provide the better UX, but it is of course more architecturally complex.
If you have specific code you are trying to get working, feel free to share and we can help.
To start with you need to understand the difference between two concepts.
Authentication and authorization.
authorization
Authorization is the act by which a user who owns private data grants an application created by a developer to access their data. Authorization is requested by showing a consent screen. A user consents to the application accessing their data, the amount of access a user grants is designated by the scopes requested.
In the image below the application Google Oauth 2.0 Playground is asking me for permission to See and download all my google drive files.
I requested the "https://www.googleapis.com/auth/drive.readonly" scope when requesting authorization.
Authorization is Oauth2. it returns an access token and a refresh token. Access tokens can be used to access api endpoints. In this case the google drive api. Access tokens are short lived and expire after an hour. The refresh token can be used to request a new access token at any time when the user is off line. This is why there is no way for an api to see if the entity preforming the call is actually the user who owns the data, it may infact be a third party application using an access token and refresh token to gain access to the users data.
You can grant an application access to your data and they can continue to request your data until you revoke that access.
Authentication
Authentication on the other hand is sign in. It is prof that the what made the call is in fact the user who owns the account. They must have typed their user name and password or logged into their account. Or already be logged into their google account on their machine. If you have two google accounts signed in like I do they you will be promoted for which user you would like to use.
So authencation authenticates or proves, that the user making the call is in fact the owner of the account the data resides on. Authentication is something called Open Id connect and was built on top of Oauth2.
The scope that are email, profile, and openid either profile or openid is required email is optional. Open id connect basically gives you access to a users profile information. If you are using a library you wont normally see this scope its normally added internally. If the only scope that is requested is a open id connect scope then the user will not see a consent screen. In the call above I added profile scope so you can see it is also asking for access to profile data but its grayed out the user cant not accept it.
Open id connect returns something called an id token. the id token is very short lived its around five minutes. An id token is a jwt so you can use jwt.io to decrypt it. Within the jwt you can find a number of claims. This claims give your application information about who the user is that just signed into your system.
Of note, name, picture, locale (language), and sub, sub is the users internal user id on the calling authentication server. So you can use the google sub id to link this users google account to your internal user storage. Then when ever this user logs in using google you will know which user it is in your system by matching the id.
{
"iss": "https://accounts.google.com",
"azp": "40740878192.apps.googleusercontent.com",
"aud": "407408718192.apps.googleusercontent.com",
"sub": "1172004532672775346",
"at_hash": "Aa0FT7DLf38T_onVI_ca8g",
"name": "Linda Lawton",
"picture": "https://lh3.googleusercontent.com/a-/AOh14GhroCYJp2P9xeYeYk1npchBPK-zbtTxzNQo0WAHI20=s96-c",
"given_name": "Linda",
"family_name": "Lawton",
"locale": "en",
"iat": 1656311886,
"exp": 1656315486
}
Note.
Sign-in will not grant you an access token unless you are able to add additional scopes to it, like drive, or calendar. I have yet been able to figure out how to add additional scopes to googles new JavaScript web login library.
The thing is what exactly are you trying to do. Do you want to log a user into your system. Or do you just want access to some private user data of theirs through one of googles apis?
In order to prevent the authorization flow to re-request for authentication, you need to add the prompt and the hint properties to the initTokenClient or the initCodeClient method config object (depending on which one of them you use - see here).
Here is how it looks like:
google.accounts.oauth2.initTokenClient({
client_id: 'YOUR_GOOGLE_CLIENT_ID',
callback: 'YOUR_CALLBACK',
hint: 'THE_USER_EMAIL',
prompt:''
});
As mentioned, the same is true for initCodeClient.
In the same way, you can pass those properties not only on initialization phase, but on the event phase as well, with the requestAccessToken or requestCode, respectively. Here it is:
googleClient.requestAccessToken({
prompt: '',
hint: 'THE_USER_EMAIL'
});
In this code, googleClient is a JS const that stores the Google codeClient / tokenClient object.
Explanation:
The prompt parameter with empty string tells Google to not request authentication if the user is already authenticated. This will let the flow to continue right to the authorization phase.
This is not enough, because if there is more then one account connected to the browser, Google can not decide to WHICH one of them he should ask for authorization API. This situation will cause the authentication popup to show again, in order to let the user to choose an account.
This is where the hint parameter comes to play, it lets Google to know what accont to use, then, if this account is already connected, Google is able to pass the entire authentication popup and go right away to the authorization one.
In order to get the user email, you should use the credential property, returned from the authentication API of google.accounts.id.initialize. This credential is a JWT string, after decoding it with the JS atob method, you'll be able to extract the user email from it, beside other properties. For more details regarding to this, please check here.

OAuth2 Requesting Additional Scopes

Using the Google Sign In SDK, a user can sign in via OAuth2 with some default scopes requested. It can be beneficial to not request every scope an app may need up front, and instead to request additional scopes at a later time so as to not overwhelm the user at sign up.
Google outlines the process for doing this here.
The issue is that, after a user has signed in with Google, upon requesting additional scopes the user has the ability to switch Google accounts and authorize those scopes using a different account before returning to my application.
Is there a way, similar to calling -[GIDSignIn signIn], to explicitly specify which user I want to signIn and not allow the option of changing accounts?
I am not familiar with Google Sign in SDK. Most of what I have done has been written myself so I don't know how that SDK really works. However that being said the Authentication server does support something called Login_hint which should allow you to force them to use a specific user.
login_hint email address or sub identifier When your application
knows which user it is trying to authenticate, it can provide this
parameter as a hint to the Authentication Server. Passing this hint
will either pre-fill the email box on the sign-in form or select the
proper multi-login session, thereby simplifying the login flow.
More info
login_hint can be the user's email address or the sub string,
which is equivalent to the user's Google ID. If you do not provide a
login_hint and the user is currently logged in, the consent screen
includes a request for approval to release the user’s email address to
your app. (Read more at login_hint.)
If memory services Google Sign in SDK does work with openId connect so it should be possible.

Enabling OAuth support in Square Connect

I have an application that currently integrates into my merchant account using my access token. Early discussion with neighborhood merchants indicates some positive interest. I want to integrate OAuth support so that I can try to get traction with those merchants.
Though https://docs.connect.squareup.com/api/connect/v1/#navsection-oauth has information, I seek some additional clarification.
(i) Access using https redirect-url is denied at Square Connect Authorize has an answer "By default the OAuth flow is disabled for applications which is why you are seeing the "Authorization not allowed" failure. If you wish to enable OAuth flow for your application then you need to contact Square." #SquareConnectSupport: I have sent an email to Developer#Square, please let me know what else do I do.
(ii) Here is how I think it will work - the OAuth integration (Please confirm)
User types in browser say "mysnow.com/square"
The Handler at "mysnow.com/square" allows user to type in an ID this ID is local to mysnow
Then the Handler at "mysnow.com/square" directs the merchant to https://connect.squareup.com/oauth2/authorize along with my application id, permissions and redirect url.
The handler then receives a notification code with AuthZ Code at the redirect URL previously provided.
Next the handler obtains the Access token (using the AuthZ code)
Finally, the handler then saves the ID, the AuthZ code , the relevant Access Token and the date/time stamp (when the token was obtained) as a tuple in a safe data store.
(iii) Using the Access Token
When there is need to access merchant data of given ID, then use the ID to get the Access Token. Use this Access Token to manage the permitted data (based on permission)
Renew the access token periodically.
​(iv) For testing purposes, I create few test/dummy merchants?​ Or do you have dummy merchant accounts that I can use for testing.
You can authorize up to ten merchants through the OAuth flow without approval from Square, which should be enough to get your integration running and tested. If you would like to make it more broadly available, you will need to contact Square about getting the app in the Square App Marketplace.
That looks essentially correct. The best practice for OAuth is something like this:
Merchant visits your landing page (e.g. mysnow.com/square) and clicks an action to start using your square integration.
Merchant's browser is redirected to the OAuth page (https://squareup.com/oauth2/authorize?client_id=YOUR_CLIENT_ID&scope=LIST_OF_OAUTH_SCOPES_YOU_NEED)
Merchant authorizes your application to access their data and is redirected back to your site. In the URL is an authorization code
Your backend makes an API call to Square to exchange the authorization code for an access token. It then uses that access token to look up information about the merchant and pre-populate fields of your signup form (e.g. you can get name, email, etc)
With a partially populated signup form on your site, merchant is prompted to complete their registration with your service.
There isn't really a way to create "dummy" merchants, but you can sign up for multiple merchant accounts with the same identity information, as long as you use a different email for each one. If you have GMail, you can do "you+someword#gmail.com" and the mail will be redirected to "you#gmail.com", so you don't need to create a bunch of email accounts to have unique email addresses.

Design for Facebook authentication in an iOS app that also accesses a secured web service

Goal:
Allow a user to authentication with Facebook into an iOS application which requires access to a protected web service that I'm running.
Assumptions:
There is a native authentication (and registration) system in place for those users that opt not to use Facebook for sign in.
Details:
Assume we want to offer the option for a user to sign in with Facebook without creating a separate account/credential for our system.
Because we support our own native auth mechanism (username and password) we have our own user IDs and issue an authentication token that is used for subsequent interactions after the initial credential validation.
I'm surprised that Facebook doesn't have best practices for this in their developer documentation. All the existing documentation is either assuming you are building FB auth into a website, or a standalone mobile app with no service that requires authentication.
Here's my initial thoughts on how this would be designed but want validation on whether it's correct.
Client pops the Facebook iOS Login
UI User signs in with Facebook credentials and gets access token
iOS App passes access token to our server
Our server talks to FB graph API using access token to (a) validate the token and (b) get the FB user ID for that access token.
e.g. Our server would call https://graph.facebook.com/me/?access_token=XYZ which would return profile info in a JSON object
Assuming it's valid, our server extracts the User ID from the JSON object and checks whether the user already has an account. If so, we issue our own auth ticket to client to use for that session. If user doesn't have an account, we create a new one with the Facebook User ID, assign our own unique UserID and issue our auth ticket.
Client then passes auth ticket back on subsequent interactions that need authentication.
This seems like the right approach to me but not sure if I'm missing something insanely basic and going down the wrong (complicated) path.
I just dealt with this myself, and here's the part that bit me:
In your step 5... It's possible for a user to register for an account with you entirely separate from their Facebook ID, right? Then some other time they log in with Facebook.... And you just created them a second account and lost their first one.
There needs to be a way to be logged in to your web service, then log in to facebook, and capture the association between the facebook ID and the local account.
Apart from that, your plan sounds solid.
Update: Facebook has added a doc outlining such a scenario HERE
Use https to transmit the auth token to your server, as stated by Facebook
Sharing of Access Tokens
Our Data Policies explicitly prohibit any sharing of an Access Token
for your app with any other app. However, we do allow developers to
share Tokens between a native implementation and a server
implementation of the same App (ie. using the same App ID) as long as
the transfer takes place using HTTPS.
One problem I can see with this strategy, is that somebody can give you an access token obtained for a different facebook app. As far as I know, there's no way to verify that the access token is for your application, so you'll just go on and use it.
It doesn't sound very harmful, though. Generally people/apps try to protect the access tokens, rather than sharing them.
One possible exploit of this would be, for somebody to create their own site or mobile app, obtain access tokens for their users and try to authenticate them, using your API. If this succeeds (the user is has a facebook account in your site), the malicious site will be able to use your API impersonating the user.
It's a bit of a long shot, but I think it could work.
Edit: It looks like there is a way to validate the access token after all. See the answer by #Daaniel on question Get application id from user access token (or verify the source application for a token).
your solution totally works.
Maybe an alternative: why not just get the email on the client from the initial social service request and send to your web service? The web service could just store the email, and maybe a social_provider as well. I understand that your web service will not be able to validate where the email came from, but isn't there a high-trust relationship between your web service and your client? If there is, seems like you can depend on the email coming from the right place. Someone please let me know what obvious thing I'm missing that makes the email-based approach silly...

Resources