How to implement social logins in MEAN stack? - node.js

I have successfully implemented multiple social logins in Node JS.
I'm stuck with the implementation in MEAN stack.
The flow I have implemented till now:
Step 1:
Button in Angular. On Click, I'm calling an API in Node which returns the OAuth URL to which the user has to be forwarded.
Step2:
Once the user enters his correct credentials, access_token is generated and sent to callback URL in Node.
Step3:
I need to send a callback to Angular, whether access_token has been generated or not. I'm not sure as to how I should pass data to Angular Page.
Is this the right approach?

so i myself am doing a mean-stack social media project and i used oauth.io,
https://github.com/oauth-io/oauth-js
its really easy to use and implementable only thing you need to know is how to import a npm package in angular.
linkedin HTML component
<html>
<header>
</header>
<body>
<a (click)="linkedinConnector()" id="linkedin-button" class="btn btn-block btn-social btn-linkedin">
<i class="fa fa-linkedin"></i> Sign in with Linkedin
</a>
</body>
</html>
linkendin TS component
import { Component, OnInit } from '#angular/core';
import 'oauthio-web';
declare var OAuth: any;
#Component({
selector: 'app-linkedin-connector',
templateUrl: './linkedin-connector.component.html',
styleUrls: ['./linkedin-connector.component.css']
})
export class LinkedinConnectorComponent implements OnInit {
constructor(private api: ApiService) { }
ngOnInit() {}
public linkedinConnector() {
OAuth.initialize('OAUTH-IO PUBLIC KEY');
// Use popup for oauth
OAuth.popup('linkedin2').then(linkedin => {
console.log('linkedin:', linkedin.access_token);
linkedin.get('/v1/companies/[company-ID]/updates?format=json').then(data => {
//do with the data what you want
});
});
}
}
however im using pop-up instead of redirect.
they have redirect too so you can implement it using there documentation
http://docs.oauth.io/

There are two ways you can do it. One is using passport.js and using OIDC client. Here are the examples for both autentication
Passport.js implementation
Oidc implementation

So when the auth token is generated. You will redirect user to some callback url along with auth token. Your node server will be listening to that url and will store user session using some node library for sessions.
Along with it what you will do is you will do a res.redirect to url on which user will land if auth token is generated if not redirect him to some other url.
Say in your angular app you have two URLs login url, logged in url.
In case auth is success :
So if auth token is generated you will redirect user to logged in url and set a session cookie for the user.
In case auth fails :
If auth token is not generated you will redirect the user to login url with some error state as part of url query params. Something like /login?auth_error=true where you can handle auth_error appropriately and show on client.
From security perspective, write a middleware on your node layer that will validate all your api requests and check if users session cookie is valid or not else redirect him to login page.
Also in my opinion, there could be multiple approaches to do this but this is how I have implemented login in my applications. So this answer is from that perspective.

In Angular you can use already available libraries for that. No need to do it yourself.
Here you have links to two such libraries that are also OIDC certified:
angular-auth-oidc-client
angular-oauth2-oidc
I add also the link to the Google instructions for OIDC authentication where you have all the necessary information to configure the libraries to use the OIDC authentication from Google.
Check also this library angular-6-social-login which provides login for Google, Facebook and LinkedIn.
This are all open source so you can still do it yourself and use the libraries as samples for how to do it.

Related

firebase onAuthStateChanged infinite loop node js

I'm using firebase to sign in my users on my node js app. I would like to see if the user is authentificated or not and after it redirect to the page I want (login if it not logged or dashboard).
But when I redirect user (if it not logged previously or session expires) it's looping on the same page (send redirect of the login page everytime when I'm on login page).
My function that I use actually :
function authenficated (req, res, next) {
firebase.auth().onAuthStateChanged(function (user) {
if (user) {
console.log("connected" + " " + user.uid);
next()
} else {
console.log("disconnected")
res.redirect('/') //loop on / page
next()
}
});
}
I would like a function that provides if my user is logged or not, if it logged my node backend return to /dashboard or other pages that I want and if not it cannot access to dashboard and it return automatically to / or /login
I specify I don't use React or Vue, I use simply EJS to display my pages
Thanks for all
This function/sdk is meant for frontend applications and not backend apps. You need to the admin sdk for that. You can use cookies and the admin sdk provides a function to create cookies. After a signin you attach the cookie to the headers and it will be send by the browser on every request. If the cookie header is empty than you know the user isn't signed in. To logout a user you can add a head method to clear the cookie.
To use backend function you need to use the admin sdk. This function is a front end function (web sdk ).
You can use onAuthStateChanged on the front end and redirect them from the front end. Remember onAuthStateChanged will fire on every page load.
OR implement cookies like the previous comments.
OR
Send the id token from the client via http request (fetch or axios) and verify server side using the admin sdk. Here is the specific link. This solution would require you to load something on the front end though and then send a http request to the backend, verify, then send protected resources after.
Cookies on the other hand are sent to the backend with every request, so if no cookie is present on the page load request then obviously there is no user. Or if the below function fails then server wont send protected resources. (this is explained in the link above for cookies)
getAuth().verifySessionCookie(sessionCookie, true /** checkRevoked */)

ReactNative - Proper approach to use Firebase token and making API calls to own server

Am using Firebase PhoneAuth for authentication in my ReactNative app and am coding my own {NodeJS, Express, MongodDB} server application for the API.
So the idea is, my app authenticates the user via the Firebase authentication, and upon successful authentication, will have the Token generated by Firebase. And this Token will be used to make any API calls to my server. And this Token is validated at my server and the corresponding response is provided.
I already asked a question about storing the Token, and Doug told me that I should listen to the onIdTokenChanged in each & every page and use the Token from there to make the API calls to my server.
Here's my minimal code:
import React from 'react'
import {View, Text} from 'react-native'
import auth from '#react-native-firebase/auth'
export default function Home({ navigation })
{
auth().onIdTokenChanged(function(user) {
if (user) {
user.getIdToken().then( token => {
console.log( token )
});
}
});
return (
<View>
<Text>Hello</Text>
</View>
)
}
Am new to ReactNative and NodeJS. So am trying to code everything properly.
My questions are:
This is an asynchronous request isn't it? I mean the fetching of the Token. So I should display a Loader in the screen by default at startup, and inside the user.getIdToken().then( token=>{ //hide the loader }) I should hide the Loader, and make the API call to my server?
If I want to make another(different) API call from the same screen, should I have to listen to this onIdTokenChanged and get the Token and then make the new API call to my server? Or should I store the previously fetched Token to a state variable using useState and then use this stored Token in the subsequent API calls from the same screen?
As you can see in my minimal code, my code for listening to onIdTokenChanged is before the rendering of the screen. Should I have to move it to the useEffect() function instead? If I moved it, do I have to unsubscribe anything inside it?

how to use passport SAML with both node (express) as backend and vue as client

I have an app with node (express) backend, and vue client.
I'm trying to add SAML SSO using passport. (makes sense to do it on the server node app).
it works perfect when used in express app. but when I applied it to a structure of express backend and vue client - it fails to make the redirection to the Idp.
when user enters my login page, vue client (Login.vue) calls node backend for verifying the user. (api verifyuser)
node call passport.authenticate('saml', ...) and I expected a response I can send back to the vue function that called me, and there, in Login.vue - to make the redirection.
but here comes the problem:
in the backend node app, the redirect response is sent after my code is executed, inside passport strategy. So it is sent automatically to the browser, not returning to the vue script that called this node api.
So the redirection is done in the background, the user don't see any redirect. the original login page is still shown.
And my vue function gets the response back from the API - only after the browser sends the redirect (in the background) to the IDP, and gets the login html page response from the IDP.
So the data I get back - is an html of the IDP login page, instead of a redirection data.
How can I solve it?
I'm new to client technologies and js and node including, so I really don't know how such a flow should be handled. searching 3 days for solution.
Thanks a lot for you assistance!
here is my snippets of code:
Login.vue:
<input class="button wide cropBottom io-mango ae-5 margin-top-0 toRight" v-on:click="userLogin" type="button" value="Log In"/>
...
userLogin: function() {
...
...
$(".overlay").show();
this.$http.post(process.env.BASE_URL + "verifyuser", oUser) //call backend node express app
.then(function(data) {
...
here I gets only an html login page which the IDP sent as a response to the redirect with the SAML Request.
}
Backend node express app:
verifyuser.js:
module.exports = function (app) {
app.post('/verifyuser', (req, res, next) => {
var SamlStrategy = passportSaml.Strategy;
passport.use(new SamlStrategy(
{ ...
});
passport.authenticate('saml', {session: false}, function (err, user, info) {
...
})(req,res,next);
//tried to get the redirect here, but res still don't have it. only after this function is called, the SAML request is created from the req, and the location url is made.
});
I've found a solution.
I changed the Vue client:
instead of calling the server using ajax, and expecting a data response to come back,
I called the server using post of a form.
that way, the browser redirects to the server when I call it, and when the passport library in the server returns a redirect response- it is done in the forground, and the user can see it.
In Single logout, passport have done a better job:
the passport API just returns the logout request created.
then I can decide myself if I want redirect from the server, or I want to send the redirection request to the waiting client function - and do the redirection from there.

Angular 5/Express/CORS with Facebook OAuth

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

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.

Resources