I have implemented the oauth workflow to get access and refresh tokens. Custom classes for OAuthAuthorizationServerProvider and AuthenticationTokenProvider are in place and working.
I'm trying to add Single Sign On functionality (to provide access to third parties through our system), but I'm not sure how it should be done or if I'm missing some pieces.
This is the workflow I would like to implement:
Third party calls /api/Account/ExternalLogin
User gets a login page where they enter the credentials
User is validated through /token call (as if they were trying to get access token)
Third party calls /token with the authorization_code to get the access_token
I'm missing something between step 3 and 4. When you validate a user, you get an access_token but you should redirect the user to 3rd party url with authorization_code so 3rd party system can get the access_token. That's what I do not get.
ok so the workflow is like this ( if I remember correctly! ):
The client will need some sort of setup on your side because you need to know to which URL to send the authorization code.
The user goes to your authorization page and inputs their username / password. If everything checks out, you issue an authorization code and redirect the user back to their URL, passing the code in the URL.
This client URL can look like this: https://www.client.co.uk/authcode_endpoint?code=blah
At this point your job is done for now.
Next, the client will receive this code on their system ( because you called their URL) and can now issue another call to you, to exchange the code for a token and the process repeats.
You send them back to another URL : https://www.client.co.uk/authtoken_endpoint?token=blah
Now they can issue more calls to do what they need to do.
Something like this should be fairly straightforward to do, you have an app to app communication basically. There must be libraries that already provide this kind of workflow for you.
Related
I'm implementing Google's 'code model' of Oauth2 and having trouble getting users' email - I wonder if this is a scopes problem or my misunderstanding about how to set up the code model. This sequence of events is already working:
Client loads https://accounts.google.com/gsi/client
Client starts call to google.accounts.oauth2.initCodeClient
Client gets code
Client passes code to one of my server endpoints
Server has an oauth2Client set up using the config with client_id, client_secret, and redirect URL = 'postmessage'
Server exchanges the code from the client for tokens
Server does oauth2Client.setCredentials(tokens) - this contains an access_token, which is enough for the client to make API calls to, e.g., retrieve the user's Google Calendar
Server is able to do oauth2Client.getTokenInfo(tokens.access_token);
There are various places along the way that involve scopes; I am probably getting something confused here. The client's initial call (step 2 above) uses
scope: 'https://www.googleapis.com/auth/calendar',
My code path on the server does define scopes anywhere.
In GCP, my project is set up with scopes
calendar.calendarlist.readonly, calendar.readonly and calendar.events.readonly
openid
/auth/userinfo.email
Here's the problem I'm encountering: when I go through this flow as a user and oauth with the account that owns the GCP project (this is a Google Workspace email, in case that matters), the tokens object that the server receives (step 6 above) has access_token, refresh_token and id_token - the id_token can be decoded to yield the user's email, and the user's email is also in the response to oauth2Client.getTokenInfo(token.access_token).
However, when I go through the flow with my other (personal) Gmail account, the tokens object that the server receives is missing the id_token but has the access and refresh tokens. Question 1: why are the responses different?
Question 2: How can I get the email of the user on the server in the personal Gmail account case? I've tried having the server make a call to https://www.googleapis.com/oauth2/v2/userinfo?fields=id,email,name,picture with the access_token, but this fails. I am not sure if I'm supposed to declare scopes for oauth2Client somehow, or tap a Google API using a different method on the server.
I think I've had a breakthrough: in step 2 in my original post, when I did "Client starts call to google.accounts.oauth2.initCodeClient", I had set the scope of initCodeClient to just the calendar scope. When I changed it instead to scope: 'https://www.googleapis.com/auth/calendar https://www.googleapis.com/auth/userinfo.email openid', (scope takes a space-delimited list in this case), it allowed my server call to get the id_token for this user and oauth2Client.getTokenInfo to get a response with the user's email in it.
When I updated the scopes like that, the popup asking for authorization also updated to request all the scopes I wanted - previously, it was only asking for the Calendar scope, so it makes sense Google didn't want to return the email.
What I still don't understand is why my previous setup was working for the account that owns the GCP project. In other words, when I was first building it out with that owner account, the client was only noting the Calendar scope while the server was asking for all three scopes (ie there was a mismatch), and the server was still able to get an id_token and the user's email in getTokenInfo. Maybe the owner account has some special privilege?
I am working with the Slack oAuth API.
When I do a GET on https://slack.com/oauth/authorize passing my client_id, and the scope, I get html reponse asking for workspace URL.
After that I need to sign in and provide my password before code is returned which I can use to renew my temporary token
My question is: How can I automate the process of providing workspace URL, username and password? I need to get the code return after authentication (the temporary token) so that I can call https://slack.com/api/oauth.access to renew my token
My reasoning is that if I have access (from the app I created) to: App ID, Client ID, Client Secret, Signing Secret and Verification Token there should be a way for me make simple API call to get code or is my understanding of the slack OAuth flow wrong?
NB: I have taken a look at https://api.slack.com/docs/oauth but I was not able to get it done. I am also aware that I can make the /signin and /checkcookie to get this done but it involves parsing HTML response for parameter values needed to make subsequent calls. I just feel there a simpler way to do it.
This Stackoverflow question is not a duplicate because is it mainly referred to a case of not having an app created; In my case, I have an app created.
This question is for anyone who is familiar with
Node.js
Express
Passport
JWT Authentication with passport (JSON Web Tokens)
Facebook OAuth2.0 OR Google OAuth2.0
I have been doing some online courses and understand how to do the two following things:
Authentication using Passport Local Strategy + JWT Tokens
Authentication using Passport Google/Facebook Strategy + Cookie/sessions.
I am trying to combine the content from these two courses basically. I want to use Google Strategy + JWT Authentication. I want to use JWT instead of cookies because my app is going to be a web/mobile/tablet app, and I need to be accessing the api from different domains.
There are two issues I am having with this:
To kick off the Google/facebook OAuth pipelines, you need to call either '/auth/facebook' or '/auth/google'. Both Oauth flows work basically the same so when I say '/auth/google' from now on, I am referring to either. Now the issue I'm having is: On the client, do I call the '/auth/google' route with a href button link or an axios/ajax call? If I use the href or axios/ajax approach I am still getting problems with both solutions.
The href approach problem:
When I assign an <a> tag with a href to '/auth/google' the authentication works perfectly fine. The user gets pushed through the Google Auth flow, they log in and the '/auth/google/callback' route gets called. The problem I have now is how do I correctly send the JWT token back to the client from '/auth/google/callback'?
After a lot of googling I have seen that people have simply passed the the JWT back to the client from the oauth callback in the redirect query param. For example:
res.redirect(301, `/dashboard?token=${tokenForUser(req.user)}`);
The issue I have with this is that now the the ability to authenticate is saved in my browser history! I could log out (destroying the token saved in localStorage), and then simply look at my browser url history, go back to the url that contains the token in the query param, and I would automatically log in again without having to go through the Google Strategy! This is a huge security flaw and is obviously the incorrect way to approach it.
The axios/ajax approach problem:
Now before I explain the problem with this issue, I know for sure that If I get this working, it will solve all issues I was having with the previous href problem. If I manage to call '/google/auth' from an axios.get() call and receive the JWT in the response body, I will not be sending the token as url param, and it will not get saved in the browser history! Perfect right? well there is still some problems with this approach :(
When try to call axios.get('/auth/google') I get the following error:
How I've tried to solve the problem:
I installed cors to my npm server, and added app.use(cors()); to my index.js.
I took a stab and added "http://localhost:3000" to the "Authorised JavaScript origins" in Google developer console.
Neither of these solutions solved the issue, so now I really feel stuck. I want to use the axios/ajax approach, but I'm not sure how to get past this cors error.
Sorry for such a long message, but I really felt I had to give you all the information in order for you to properly help me.
Thanks again, looking forward to hear from you!
I solved this in this way:
On Front-End (can be mobile app) I made login request to Google (or Facebook) and after the user selected his account and logged in I got back response that contained google auth token and basic user info.
Then I sent that google auth token to backend where my API sent one more request to the Google API to confirm that token. (See step 5)
After successful request comes you get basic user info and e-mail. At this point, you can assume that user login via Google is good since google check returned that it's okay.
Then you just signup or login user with that email and create that JWT token.
Return token to your client and just use it for future requests.
I hope it helps. I implemented this multiple times and it showed like a good solution.
Though there is good answer, I wanted to add more information with example.
Passport's google/facebook strategy is session based, it stores user info in cookie which is not advisable. So we need to disable it first
To disable session we need modify our redirect router. For example if we have redirect path /google/redirect like following, we need to pass { session: false } object as parameter.
router.get('/google/redirect', passport.authenticate('google', { session: false }), (req, res)=> {
console.log(":::::::::: user in the redirect", req.user);
//GENERATE JWT TOKEN USING USER
res.send(TOKEN);
})
So where does this user come from? This user comes from passport's callback function. In the previous snippet we have added passport.authenticate(....) This middlewire initiates passport's google-strategy's callback which deals with the user. For example
passport.use(
new GoogleStrategy({
callbackURL: '/google/redirect',
clientID: YOUR_GOOGLE_CLIENT_ID
clientSecret: YOUR_GOOGLE_SECRET_KEY
},
(accessToken, refreshToken, profile, done)=>{
console.log('passport callback function fired');
// FETCH USER FROM DB, IF DOESN'T EXIST CREATE ONE
done(null, user);
})
)
That's it. We have successfully combined JWT and Google/Facebook Strategy.
The solution I found was to do the OAuth flow in a pop-up (window.open), that makes use of a pre-defined callback to pass the token to the front-end upon successful authentication.
Below are the relevant code samples, taken from this tutorial:
https://www.sitepoint.com/spa-social-login-google-facebook/
Here is the pre-defined callback and initial open method, called from your front-end:
window.authenticateCallback = function(token) {
accessToken = token;
};
window.open('/api/authentication/' + provider + '/start');
And here is what your OAuth Callback URL should return, upon successful authentication (which is the last step/page inside your pop-up):
<!-- src/public/authenticated.html -->
<!DOCTYPE html>
<html>
<head>
<title>Authenticated</title>
</head>
<body>
Authenticated successfully.
<script type="text/javascript">
window.opener.authenticateCallback('{{token}}');
window.close();
</script>
</body>
</html>
Your token would now be available to your front-end's pre-defined callback function, where you could easily save it in localStorage.
I suppose though, you could do the OAuth flow in the same window then (sans pop-up) and return an HTML page (similar to the above) that just saves the token and redirects the user to a dashboard immediately.
If your front-end domain was different from your api/auth server, however, you would probably need to redirect from your api/auth server to your front-end with a single-use, time-sensitive token (generated by your api/auth server), that your front-end could then use to call and receive (with axios) your actual token. This way you wouldn't have that browser history security problem.
So I'm trying to do google oauth to get a refresh token for my users (not actually using google oauth to save the user). I had everything working when I used the client side OAuth for google api but they don't provide a refresh token when you do that handshake, only an access_token. I need a persisted refresh_token since I'm going to be making a lot of requests to the users google calendars.
So I set up omniauth on my rails server to make the flow go like this:
user clicks authenticate with google (client side) -->
popup screen goes to backend server (localhost:3001/users/auth/google_oauth2) -->
backend rails server redirects to google for authentication -->
they authenticate with google and get redirected to backend server's callback (localhost:3001/users/auth/google_oauth2/callback) -->
backend server saves token for appropriate user and then redirects back to client side app on localhost:3000 (nothing needs to be done on client, just need the token saved on my server for future use)
I do however need to know that the authentication was successful so I can dispatch appropriate actions in react/redux. In redux-auth they check for the access_token inside the popup.location URI. Problem is when I use this server side popup flow I get this nasty http/https error:
(original image: http://imgur.com/v5NgIGr)
If instead of redirecting back to the client I just redirect to a view in my backend server I could then have a script on that page that just does window.close() which works but seems hacky to me. Another potential solution I was thinking was to try and use the window.postMessage api but I don't know if that has great browser support/also seems hacky. I could emit a message to the other window (the main client app) from the popup saying the oauth was successful so my react code and do whatever it needs to do.
I feel like I'm just approaching this whole flow completely wrong or I'm missing something obvious.
I also feel like if I just had HTTPS on everything it would all work since before when it was 100% client side the popup worked beautifully and I didn't get this SecurityError. I spent some time figuring out how to get my webpack dev server using https and tried doing the same with rails (think I did something wrong on the rails side) but it was still not working. Also feel like I shouldn't need to force HTTPS on all my development servers in order to get it working...
If anyone has any thoughts or could give me some direction that would be much appreciated!!
You are approaching this the wrong way. Google's authentication and their APIs do have confusing documentation. I was also stuck with similar situation and after spending considerable time, I found the right way to do this.
From your question, I believe this seems like the relevant link: https://developers.google.com/identity/sign-in/web/server-side-flow
And following it, here is how your flow should look like:
To map it on your problem, this is what you will do:
user clicks authenticate with google (client side)
Client requests Google for authorization that includes your scopes
and receives a one time authorization code.
Client Sends this authorization code to your ruby server.
Ruby server uses the authorization code to exchange it with access_token and persisted refresh_token which you shall use in your subsequent requests to google apis.
Hope it helps.
I'm only starting to explore what OAuth and I have barely any clue of the related terms.
In a PHP code snippet, I saw :
// Callback can either be 'oob' or a url
$callback='oob';
I'd like to know what oob is?
oob usually stands for "out of band". I would assume that this is to support OAuth responses that come through an unspecified method.
OOB ("out of band") is an alternative to the traditional 3-step process of an OAuth flow (known as 3-Legged-OAuth). The user is not redirected after granting access to a consumer, instead, a code is shown to the user which he needs to manually input in the Consumer App. The difference is outlined in the step 2b below.
An OAuth1a flow:
Step 1: Get a short lived request_token which can be used to access the User Authorization URL.
Step 2: Use the request_token to access and show the User Authorization URL to the user. The user will see a screen where he can accept or decline access; the tipical "Do you want to give App ABC access on your behalf?".
Step 2a (callback url): If a callback_url has been provided, the user will be redirected to that callback URL. The URL will include the parameter oauth_verifier which contains a code, needed for step 3.
Step 2b (callback is oob): If the callback_url is set to oob, the user will not be redirected. Instead, the oauth_verifier code is shown to the user. This must be implemented by the Provider. The user can use this code in the Consumer App, usually a mobile app or any other non-browser based App, to continue to step 3.
Step 3: The oauth_verifier code (and Request Token) is used to get a long-lived access_token. The Consumer can now make calls to the (REST)-API of the Provider using this token in his OAuth calls (the request still needs other OAuth parameters and needs to be signed etc.).
Further info:
Pin based authorization with Twitter API
OAuth1a core specification - Request URLs