Angular 5/Express/CORS with Facebook OAuth - node.js

So I'm having a problem getting my MEAN stack application to provide oauth with Facebook using PassportJS. Namely, I can't figure out how to get CORS to work on the Angular side of the application.
In my application the angular application sends a get request through a user facing click action:
<button (click)="onFacebookLogin()" class="loginBtn loginBtn-facebook">
<span><img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/14082/icon_facebook.png"/></span>| Login with Facebook
</button>
which eventually leads to this get request in my loginService:
facebookLoginUser(): Observable <User> {
return this.http.get('users/auth/facebook')
}
This of course takes me to my route which uses passport.js:
// This part is in a 'users' module which is why you don't see 'users' prepend the route
router.get('/auth/facebook', passport.authenticate('facebook', {
scope: ['email', 'photos']
}))
Now this piece of code returns an error from Facebook saying that 'photos' is an improper scope (something that I will address later). My problem is that the request delivers no error to my server and instead delivers the error (and I would presume the eventual object) to the angular application (I see the error in the browser console). The browser, naturally, complains about this since facebook is trying to communicate with it on a request that it didn't initiate (cors). My question is, how do I fix this?
Recommendations from this SO question say that I must navigate to the suggest that I need to navigate to the page that I'm making the request from. I've tried making the button a link with an anchor element and href but that doesn't work. Also that question uses angular.js and I don't think providing a new route with my router and creating a whole new view seems very prudent. Besides that, I still feel like Facebook would be returning the user to the angular application and not my express application like I intend. Does andybody know what I should do?
Update
Error Code
Failed to load https://www.facebook.com/dialog/oauth?response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fauth%2Ffacebook%2Fcallback&scope=email%2Cphotos&client_id=2087173708182970: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access.

As CBroe commented, the method I was using to make the call was wrong as it couldn't be performed in an ahax-y way. I ended up using an anchor tag with an target=_blank attribute with an href that pointed directly at my backend passport facebook oauth route. So something like this:
<a href="http://localhost:3000/users/auth/facebook" target="_blank" class="loginBtn loginBtn-facebook">
<span><img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/14082/icon_facebook.png"/></span>| Login with Facebook
</a>
Everything works now

Related

JSON Web Token (JWT) is too long to pass through client URL? Node.js and Express authentication

I am trying to use JWT to authenticate a user's email address. I cannot use OAuth because a user will be signing up with their work email and will need to verify using that.
I have added a field to my User model called isVerified. I have used mailgun to send an email to the user when they go to sign up that includes a link to a verification page in the form of http://{client_url}/verification/{userToken} where the userToken is a generated token using JSON web token.... the token is created using only the user's id so there is not a lot of information in the payload.
When the user clicks on this link, they are getting a 404 Not Found error. When I manually shorten the userToken in the url, then it properly connects to the correct React Component...
How do I solve this issue?
UPDATE: I just got rid of all the periods from the JWT token and it is loading like that.... so it seems to not be an issue with the length but with the periods... My react router Route path is "/verification/:userToken" ... how do I get it to not be affected by the periods?
Since this does not trigger your component to be rendered
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjIyLCJpYXQiOjE2MTEwMDY5OTUsImV4cCI6MTYxMTAwODE5NX0.D_-RI_YvE6lyHZFtkMizuHxPs3huIE87D6UKFEywYdg
and this does
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
I would suspect that it somehow worked because you got rid of the dots.
Make sure the "." in the token prevent the url from matching your "verification/token" route ? I mean react is assuming that
"verification/eyxxxx.eyzzzz"
is not a valid route.
Try calling for example "verification/test.test.test" and see if it renders your component.

Google OAuth2: Redirect has been blocked by CORS policy: Request requires preflight, which is disallowed to follow cross-origin redirect

Trying to implement Google OAuth2 and using https://github.com/google/google-api-nodejs-client#authorizing-and-authenticating as reference. When redirecting user to consent page like this
var url = oauth2Client.generateAuthUrl({
access_type: 'offline',
scope: some_scope
});
res.redirect(url);
I get this error in browser console (links edited):
XMLHttpRequest cannot load localhost:8080/myPageName. Redirect from localhost:8080/myPageName to accounts.google.com/o/oauth2/auth?access_type=... has been blocked by CORS policy: Request requires preflight, which is disallowed to follow cross-origin redirect.
The strange thing is that I am getting this error only when executing the flow from GUI (user presses the button; angular2 front-end). When I put localhost:8080/myPageName directly into the browser address bar everything works fine (get consent form and then tokens).
Any help is appreciated. Thank you.
I had the same issue (with a react frontend, but it's the same).
This is probably because from the server you use redirect, which triggers CORS (even if from your server you allow it).
you have to return the redirect URL to your front-end in some other way, capture it from the front-end app and then call the URL you need to invoke.
A simple solution is create a hidden link with the required query parameters and click the link using JavaScript, if google supports HTTP POST submission then a hidden form can be created and submitted directly again using JavaScript magic to bypass the CORS restriction which I guess is either already removed or will be removed in near future.

Handling redirect code with OAuth2

I am using Instagram's API which requires OAuth2 have some questions regarding best practice for setup. For more details here: https://www.instagram.com/developer/authentication/
So a user clicks on a login button and I give a redirect href.
Log In
They then receive a popup sign in, and they have the option of signing in or not. They are then redirected and '?code=zzzzzzz'is appended to the url: "http://localhost:8080?code=zzzzzzz"
Then the instructions read:
Now you need to exchange the code you have received in the previous step for an access token. In order to make this exchange, you simply have to POST this code, along with some app identification parameters, to our access_token endpoint.
But how should I do this? I'm using Express on the backend. To serve the frontend I use this line:
var static_path = path.join(__dirname, './../build');
It isn't an API route, so I can't use the normal
app.get('/?code=zzzzzzz', function(req, res) {...}).
So how can I use the code that I received in the params?
You must change your redirect_uri on isntagram to something like:
/auth/instagram/callback
https://api.instagram.com/oauth/authorize/?client_id=CLIENT-ID&redirect_uri=http://localhost:8080/auth/instagram/callback&response_type=code
Then you can get your code with req.query.code from inside the controller.
For posting the code to isntagrams API use "request" library for nodejs

Show public logic if user is not authenticated React JS and Node API

How can I show only public(i.e: home, about, authentication stuff) if the user is not signed in?
I know SPA's are not meant to refresh, but I want it to change most of the scripts on the page.
Environment: Using ReactJS, WebPack with an existing NodeJS API, both on separate projects.
I went through Webpack documentation and understood that it will load only the required scripts and components, but all scripts can be seen with "View Page Source". If I understood it the wrong way, please correct me.
Ideally you track if the user is logged-in or not by storing a sessiontoken somewhere in your application state tree. You can use something like Redux to manage state in your application. You first need to decide which route you need to redirect to if the user is not logged-in & requests a route which requires authentication. Lets assume you have 2 routes /login and /products. You want to ensure that only authenticated users can view the /products section. The way you accomplish this is by redirecting to /login by checking the sessiontoken value of your state which you can pass as props to your Products component mapped to the /products route.
Use something like react-router
In the Products component use something like below
class Products extends Component{
componentWillUpdate(nextProps, nextState, nextContext) {
let {sessiontoken}=nextProps;
if (!sessiontoken)
nextContext.router.push('/login');
}
}
Products.contextTypes = {
router: React.PropTypes.object.isRequired
}
In the code above we are reading the value of sessiontoken which is passed as props from a higher order Container component. In case there is no sessiontoken it will redirect to /login. As long as your APIs return an HTTP 401 on encountering an invalid sessiontoken this will work perfectly for you and you don't need to worry about people being able to view page source.

NodeJS - Not being able to access the route I want

I'm having some troubles getting to a route I got. The route works on http://localhost:3000/me and shows info but on http://localhost:3000/!#/me it doenst show anything. The purpose of said route is to show the logged persons' profile.
On my server routes I got:
app.get('/me', users.me);
The users.me function is as follows:
exports.me = function(req, res) {
res.jsonp(req.user);
};
The console states it expected a object and got an array, I can understand that since I'm getting a json, but how can I send the own user back to the front-end so it shows his/her profile?
Edit: I managed to solve my problem, since I use passportjs I can get the user id from the session. Since I already had a route for a user by id, I simply had to redirect to said route. Like this: req.redirect('users/'+ req.session.passport.user);. Since I already had a /users/:userId route working it completely solved my issue.
Edit2: Apparently there are several ways to get the user id. Try to console.log the request and you will see what I mean :)
/me and /!#/me are not the same route . The later won't match get('
/me',..)
the hash fragment #/me will not send to the server, you cannot capture that by server side routers(without force the page refresh by client code). But you can manage that by client-code.

Resources