I have a RESTful back-end server with basic authentication. Currently I am implementing a front end page with AngularJS to interact with the server. Can anyone give me some hint about implementing the basic authentication in AngularJS? Do I need to use Interceptors?
Thanks
By basic authentication did you mean HTTP Auth? Anyway - if you need to send authenticated requests from Angular to your back-end server, then yes you would need to use HTTP interceptors.
I found this article very helpful when I was implementing token based auth w/ Angular before: https://auth0.com/blog/2014/01/07/angularjs-authentication-with-cookies-vs-token/ - but there are a lot of resources out there on this.
You can use post method and handle the result(i.e., if login Success set some flag success to true else set success to false).
backendURL = "http://someurl";
postData = { username: 'USERNAME', password: 'password' };
$scope.serverCall = $http.post(backendUrl, postData);
$scope.serverCall.success(function(result,status,header,config){ //handle your result })
$scope.serverCall.error(function(result,status,header,config){ //handle your Exceptions })
Note: Login fail or Success it will come to success callback only. In case Exceptions in the backend then only it will come to the error callback.
In the Backend Side
{ success: true } // If Login Success
{ success: false } // If Login Fail
Based on this flag you can handle it.
I Hope this will helpful.
Related
I want to have a login button in my website so when a user clicks on it, the user can use their Google credentials. I'd like to ideally perform the authentication server side using Express.js and Passport.js.
I implemented authentication server-side but the problem is that I can't make an AJAX request from the website to the server to start authentication because Google or Oauth don't support CORS. So I need to use a href element in my website which would call the server authentication endpoint. However, I can't catch server response in this way.
If I perform the authentication client-side (I'm using React) I could store login state in Redux and allow the user to access the website's resources. However, when the user logs out I need to make sure that server endpoints stop serving the same user which feels like implementing authentication twice: client-side and server-side.
In addition when authenticating client-side, Google opens a popup for the user to authenticate which I think is worse user experience then just a redirect when authenticating server-side.
I'm wondering what the best practice in terms of authenticating using Oauth2/Google. For example, stackoverflow.com also has Google button but just makes a redirect, without any popup, so I guess they figured out a way to perform server-side authentication and to bypass CORS issue.
I faced the same issue. This article is Gold link
1.In auth route File I had following code
const CLIENT_HOME_PAGE_URL = "http://localhost:3000";
// GET /auth/google
// called to authenticate using Google-oauth2.0
router.get('/google', passport.authenticate('google',{scope : ['email','profile']}));
// GET /auth/google/callback
// Callback route (same as from google console)
router.get(
'/google/callback',
passport.authenticate("google", {
successRedirect: CLIENT_HOME_PAGE_URL,
failureRedirect: "/auth/login/failed"
}));
// GET /auth/google/callback
// Rest Point for React to call for user object From google APi
router.get('/login/success', (req,res)=>{
if (req.user) {
res.json({
message : "User Authenticated",
user : req.user
})
}
else res.status(400).json({
message : "User Not Authenticated",
user : null
})
});
2.On React Side After when user click on button which call the above /auth/google api
loginWithGoogle = (ev) => {
ev.preventDefault();
window.open("http://localhost:5000/auth/google", "_self");
}
3.This will redirect to Google authentication screen and redirect to /auth/google/callback which again redirect to react app home page CLIENT_HOME_PAGE_URL
4.On home page call rest end point for user object
(async () => {
const request = await fetch("http://localhost:5000/auth/login/success", {
method: "GET",
credentials: "include",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
"Access-Control-Allow-Credentials": true,
},
});
const res = await request.json();
//In my case I stored user object in redux store
if(request.status == 200){
//Set User in Store
store.dispatch({
type: LOGIN_USER,
payload : {
user : res.user
}
});
}
})();
5.last thing add cors package and following code in server.js/index.js in node module
// Cors
app.use(
cors({
origin: "http://localhost:3000", // allow to server to accept request from different origin
methods: "GET,HEAD,PUT,PATCH,POST,DELETE",
credentials: true // allow session cookie from browser to pass through
})
);
Your authentication should be done server side. Here is how it works.
You make a fetch or axios call to your authentication route.
Your authentication route sends a request to Google's Authentication servers. This is important to have on the backend because you will need to provide your clientSecret. If you were to store this on the frontend, it would make it really easy for someone to find that value and compromise your website.
Google authenticates the user and then sends you a set of tokens to your callback url to use for that user (refresh, auth, etc...). Then you would use the auth token for any additional authorization until it expires.
Once that expires, you would use the refresh token to get a new authorization token for that client. That is a whole other process though.
Here is an example of what that looks like with Passport.js: https://github.com/jaredhanson/passport-google-oauth2
EDIT #1:
Here is an example with comments of the process in use with Facebook, which is the same OAuth codebase:
https://github.com/passport/express-4.x-facebook-example/blob/master/server.js
Redux can really help with achieving this and this follows the same logic as Nick B already explained...
You set up oauth on the server side and provide an endpoint that makes that call
You set up the button on you react frontend and wire that through an action to the endpoint you already setup
The endpoint supplies a token back which you can dispatch via a reducer to the central redux store.
That token can now be used to set a user to authenticated
There you have it.
I am developing a MEAN application. I am using passport for authentication- local, facebook and google strategies.
I am using angularjs client. All the routing is handled at client. I am only consuming server data apis.
When using passport-facebook strategy, I am using below code at node server as per passport docs.
app.get('/auth/facebook',passport.authenticate('facebook-auth', { scope : ['email'] }));
app.get('/auth/facebook/callback',passport.authenticate('facebook-auth', {
successRedirect : '/home',
failureRedirect : '/login',
scope:['email']
}));
Problem I am facing is when user click on "Sign in using Facebook" button
<i class="fa fa-facebook"></i> Sign in using Facebook
Client will access "/auth/facebook" route that will eventually redirect user to facebook page for validating user's credentials.
After successful validation, user will be redirected to route "/home" as defined in "successRedirect" value.
Now the thing is, I want to use custom callback function instead of defining redirects for success or failure. It will look like below:
app.get('/auth/facebook/callback',passport.authenticate('facebook-auth', function(err,user,info){
if(err){
throw err;
}
else if(user === 'userexists'){
res.json({
'state':false,
'message':'User with this e-mail already exists'
});
}
else{
req.logIn(user,function(loginErr){
if(loginErr){
throw loginErr;
}
res.json({
'state':true,
'message':'You logged in successfully!'
});
});
}
}));
The root problem I am facing here, I can not use above custom callback as Client is not calling the "auth/facebook/callback" route, it is called by facebook.
So, there is no success handler waiting to catch above callback's response at client side!!
I want some way to get response in json form at client to eliminate server side redirection and also way to pass message and username to client after successful authentication by facebook.
I am about to give up with passport. Hoping for any possible solution before removing a lot of code!
Thanks
This can be accomplished by redirecting to another endpoint inside the facebook callback handler. There is no need to do res.json() on the callback from facebook since they only make a request to that in order to let you know if auth failed or succeeded. From their docs:
// GET /auth/facebook/callback
// Use passport.authenticate() as route middleware to authenticate the
// request. If authentication fails, the user will be redirected back to the
// login page. Otherwise, the primary route function function will be called,
// which, in this example, will redirect the user to the home page.
So facebook returns control over request process back to you when they call /auth/fb/callback but it's up to you what to do next. Since once the user is successfully authenticated, you would have req.user available throughout the whole session. At this point, you can redirect to something like the have in the example /account and check if req.user with req.isAuthenticated() and complete the flow you desire.
A bit of background:
I am using Passport.js to handle login from serverside.
Angular routing is used on the client side in a one-page-app
The issue:
In my server router i have middleware which ensure users are logged in when requesting certain content, namely:
function isLoggedIn(req,res,next){
if(req.isAuthenticated()){
return next();
}
res.render('index.ejs');
};
used in routes such as:
app.get('/SomethingForLoggedUsers', isLoggedIn, function(req,res){...
My problem is that if the user is on the website (on the part handled by Angular router) and their session is expired res.render('index.ejs'); does not work. My feeling is that angular routing has to do with the fact that index.ejs is not shown, but I don't manage to fix the problem. Any suggestions?
The problem with your solution is that with angular, it is possible that the user may be doing some client operations and not making a request on the server.
In angular, I have seen two common approaches to this problem:
Handle this fully on the client, there is an open source ng-idle directive that can help with this. When the user times out on the client, you can log them out of the application using passport
Handle this with support from the server, there is an open source angular-http-auth module that can help handle HTTP 401 / 403 from the server. This means your code would do:
function isLoggedIn(req,res,next){
if(req.isAuthenticated()){
return next();
}
res.writeHead(401);
res.end();
};
I hope this information helps you understand what is possible in Angular.
Here is how I solved the problem.
In my angular controller I have:
$http.get('/SomethingForLoggedUsers').success(function(data) {
if(!data.user)$window.location.href="/login";
and in the server I return user:null everytime the user is not logged, namely:
function isLoggedIn(req,res,next){
if(req.isAuthenticated()){
return next();
}
res.json({user:null});
};
I authenticate my user only through laravel, so angular does not know about it. But I need to do a $http.post on a "before auth" route with angular in order to get some profil info:
laravel route.php
Route::post('profile', array('before' => 'auth', function()
{
// Only authenticated users may enter...
}));
angular app.js
$http.post("/profile").success(function (data) {
$scope.profile = data;
});
For now I get an internal server error (500) with a "Illuminate\Session\TokenMismatchException" because laravel think I'm not logged in.
Could someone help me out with this?
Thanks in advance :)
My mistake, it was a csrf filter that was causing this error, not the auth filter...
For reference to my question:
AJAX Requests are identical with regular requests in regards to session data. Anything that depends on Session or Auth will work with an AJAX call.
link to thread
I am fairly new to AngularJS
I have a resource that I use for user management which is part of a service following this article.
Once sending the login request to the server I am getting a response with a set-cookie as part of the header.
What is the best practice to add this cookie to every request I am sending to the server?
myApp.factory('UserService', ['$resource', function ($resource) {
var userRes = $resource('http://<MyDomain>/api/v1/user/:param',
{param: '#param'},
{
login: {
method: 'POST'
},
logout: {
method: 'DELETE'
}
});
var user;
return {
signIn: function () {
user = userRes.login({param: 'login'}, {"email": "SomeName#MyDomain.com", "password": "test1"});
userRes.get({param: '1'});
},
userRes.login has set-cookie header in on the response
userRes.get does not send the cookie that was just received.
Cheers
Since your API is in a different domain you can't use cookies in this case. We've tried and we failed to put it simple there is no way, not only it doesn't work with CORS but also it doesn't work if you embed an iframe. The iframe trick fails on safaris mostly but it is not reliable.
What we usually do is to return a JWT (Json Web Token) from the API and attach a header then to every API request as Authorization: Bearer JWT.
This JWT can be decoded using a public key from the front end (and it will contain the user profile) and validad with a private key in the backend.
JWT is simple and there are plenty of libraries for every language/technology.
Auth0 is an authentication broker that can validate with any identity provider or custom databases, and it returns JWTs using standars. It provides a clientID that can be used to decode the profile in the front end and a secret to validate the tokens in the backend as well as client side library to do this.
Disclaimer: I work for auth0.