I'm having a good time with Satellizer, except in one case - the Twitter oAuth 1.0a flow. The popup does not close after successfully authenticating a user.
My configuration is;
$authProvider.twitter({
url: '<my server endpoint to get request token (POST)>',
redirectUri: '<my server endpoint to perform oAuth login (GET)>'
});
I have set the callback URI for my Twitter app to be the same as redirectUri (and I also pass it when getting a request token from Twitter).
The flow that I see is this (basically, I get to Step 10 in the oAuth 1.0 flow and then the popup does not close):
User clicks the "Sign in with Twitter" button
The popup appears and an empty POST call is made - my server returns the request token
The user clicks "Authorize Application"
My server receives a GET request for the oAuth login (not a POST as the documentation says I should)
My server correctly authenticates and returns the Bearer token.
And then nothing - it all stops. I suspect because I am responding to a GET not a POST but I can't figure out what is causing the GET.
Any help would be greatly appreciated!
Ben
Apologies everyone - this is my fault. Per my comment above, once I set the redirectUri properly and used just the /auth/provider method it all worked.
Quite simply, on the second call the parameters come through (correctly) in the body. Once I realised that, extracted them, authenticated, and then returned, it all worked like a charm.
Related
I've successfully implemented Discord's OAuth2 flow using the authorization code grant type into my application. The end user navigates to Discord's OAuth2 link for my bot, authorizes its access, and Discord redirects them back to my site with a code querystring. The bot then exchanges this code for an access token by querying Discord's API. Documentation on this process is available here for reference.
However, roughly every 50-100 requests to the exchange endpoint, I receive a 403 with the error invalid_grant and the description Invalid "code" in request. Frankly, I don't understand how the code just provided by Discord's system is instantly invalid. The same user can complete the process again and no error is returned the second time.
Out of desperation, I tried toggling on the option in the Developers Dashboard named Requires OAuth2 Code Grant seeing that it said "if your application requires multiple scopes," but it made no effect. I've also tried endless debugging, but the circumstances under each occurrence are apparently random. Oddly enough, I can't find anyone with the same issue online.
Below is the request I'm making in Node.js using the superagent library. It matches the documentation and works perfectly, other than the response randomly being the error described.
superagent.post('https://discordapp.com/api/v6/oauth2/token')
.type('x-www-form-urlencoded')
.set('Content-Type', 'application/x-www-form-urlencoded')
.send({
client_id: process.env.BOT_ID,
client_secret: process.env.BOT_SECRET,
grant_type: 'authorization_code',
code,
redirect_uri: process.env.OAUTH2_REDIRECT_URI,
scope: 'identify guilds.join',
});
I can confirm that all variables match their expected values. The value of redirect_uri matches that of redirect_uri in the original URL used. code is the value of the code querystring returned through the OAuth2 flow.
What (if anything) am I doing wrong that's causing the error?
Update 1:
Discord has directed me to the API GitHub repo, and I found the issue closed here. Commented and will update here if I receive any helpful info or resolve the issue completely (hopefully the case).
Ran into the same issue using nodejs. Leaving here notes for prosperity:
On Node, if there is no explicit app.head() handler, the .post() handler receives all head requests
Several Android phones, upon being redirected from discord, first send a head request to the endpoint
Meaning:
The user authenticates on discord, then through the redirect back, does a head request. This pulls discord with the code, BUT directly afterwards it also does a post request, which will fail (as you already used the code once), and possibly un-authenticates the user.
Solution for my specific issue was an explicit .head handler for all callback endpoints, which basically just returned the same headers (a redirect) as the post one did, but without calling discord.
Hope this helps.
did you use the OAuth2 link to invite your bot to your server - with the correct permissions? If so, in your main.js file did you define the token?
I.e. bot.login(“YOUR_TOKEN_HERE”)
I would recommend not toggling the ‘Requires OAuth2 Code Grant’ as it is a pain to do anything with in the beginning.
Please let me know of any progress :)
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.
I have a hobby project in mind to use battle.net login. I'm wondering how I can obtain the access token from the API after receiving the authorization code.
This is Oauth flow question rather than a battle.net question.
Currently I can successfully authorize the user for my app which is registered in dev.battle.net and then I try to use the authorization code returned from the battle.net login to obtain the access token by sending a request to https://<region>.battle.net/oauth/token.
However I keep receiving this error:
{
"error": "unauthorized",
"error_description": "An Authentication object was not found in the SecurityContext"
}
I use postman extension to send post requests to that uri. I authenticate my request with my client id and secret. I pass redirect_uri (https://localhost), granty_type (authorization_code), code(the code returned from the previous authorization step). However I keep getting the error above.
I couldn't find much about battle.net online. There are other oauth related help articles but couldn't really find my way.
Wondering if you can help me with this easy stuff. I'm just wondering what I'm skipping here.
Here is the documentation:
https://dev.battle.net/docs/read/oauth
https://localhost is added in my mashery dev account's app settings.
Me again, I resolved this problem after trying almost every combination in the universe:)
Steps to apply:
Don't use the same authorization token for different access token trials, they are not valid
Always use https on every domain you test including localhost, you
redirect_uri must be https as well.
You must use the "basic authentication" in the header of your POST request while requesting the token from the authorization code you obtained from the previous step.
This is one of the most important ones: For requesting token, Pass redirect_uri, client key and secret as POST form parameters to the authenticated request. This is interesting because it's already an authenticated request; why would i need to pass my secret again? Anyways, that's how it works.
Here are the full text:
http://hakanu.net/oauth/2017/01/26/complete-guide-of-battle-net-oauth-api-and-login-button/
This is working prototype:
https://owmatch.me
Thanks.
I'm using this site https://msdn.microsoft.com/en-us/library/azure/dn645542.aspx to do Authorization Code Grant Flow with the goal of reading my office 365 calendars using this type of flow. The problem is that when I request for an oauth token the response is not updating the "scope" variable. I'm requesting the oauth token using this POST call "https://login.microsoftonline.com/common/oauth2/token" and passing in the body my grant_type, redirect_uri, client_id, client_secret, code, resource. The response is 200OK but for scope it only reads -> "'scope': 'Contacts.Read'" when it should also have Calendars.Read as well. In manage.windowsazure.com for the app that has the same client_id I'm passing in has the read calendars checked as well as the read contacts checked. When I first got my authorization code by typing this into the browser "login.microsoftonline.com/common/oauth2/authorize" I only had "Contacts Read" checked. But now every time I type that into my browser it skips the page where I accept my app to look at my calendars and contacts page. When I login with someone else's computer and get the auth code and request the token it updates their scope to both contacts and calendar and works fine. For me I'm getting a new Auth code in the url but it skips the page where I could accept my app to look at my contacts AND calendars. I'm getting a new authorization each time. I tried clearing my browsing data but It still wouldn't work.
You need the user to logon again so they can consent to the new scope. Try adding prompt=consent to your logon URL.
This works much nicer in the v2 app model, which does dynamic scopes.
I have been trying with the simple REST Client as well as the REST Plugin for Mozilla. I am getting
"HTTP/1.1 401 Unauthorized" response with
"{"error":"unauthorized_client","error_description":"the client is not authorized"}" in the body.
I have been successful in getting the auth code, and the below is the POST request for access token, (Scope is r_fullprofile)
https://www.linkedin.com/uas/oauth2/accessToken?grant_type=authorization_code&code=AQTQeBxBzbU2aNWaQM6Ff3Z3bUd8Gyg10W9G2DdqXgWiP0q7-M55c5PLtppP7Ni3Y-6A9C8yDkj9K4VfJ7QkRUFjuV-3AknA5jAahpsFJv3wYfr8XD8&redirect_uri=https://www.google.com&client_id=75wl6j5zndvfkp&client_secret=secret
The redirect_uri=https://www.google.com is the one used for getting auth code as well.
Do we need to perform any URL encoding before making the POST request?
When I log into the linked in to my app, it has the below tokens,
OAuth User Token: c3ae4cee-1b23-xxx-9d2a-206f578dee4d
OAuth User Secret: 76bc48cc-c94f-xxx-bf9d-a663f7003383
I am not sure where it is used. we are using API & secret key to get auth code.
Thanks in Advance.
This is a 2-step process.
First, go to:
https://www.linkedin.com/uas/oauth2/authorization?response_type=code&client_id=YOUR-API-ID&scope=r_basicprofile&state=STATE&redirect_uri=YOUR-ENCODED-REDIRECT-URI
Then, within 10 secs of receiving the response, go to:
https://www.linkedin.com/uas/oauth2/accessToken?grant_type=authorization_code&redirect_uri=YOUR-ENCODED-REDIRECT-URI&client_id=YOUR-API-ID&client_secret=YOUR-API-ID&code=THE-CODE-OBTAINED-IN-FIRST-STEP
The response of the second request will have the actual access token you need to use.
When I followed the two steps I faced an issue where I got an error as
{"errorCode":0,"message":"Access to posting shares denied","requestId":"TYWULO2WPZ","status":403,"timestamp":1497353538016}
So I had to remove the &scope=r_basicprofile since it was preventing reading all the Default Application Permissions
I faced a similar problem and the problem was with the initial authorization code. You should mention the scope=rw_company_admin or whatever it is that you want to authorize to while doing the initial redirect URL call. Something like this -
https://www.linkedin.com/oauth/v2/authorization?response_type=code&client_id=your_client_id&redirect_uri=https%3A%2F%2Fwww.google.com/&state=12345&scope=rw_company_admin%20r_emailaddress%20w_share%20r_basicprofile