Token API and Backend Google OAuth in Node and Angular - angularjs

We are transitioning from an API using cookies for state (ExpressJS sessions) to a stateless (token) API.
We use a single PassportJS authentication strategy (GoogleStrategy). When the OAuth flow completes, Google calls back to a backend route with an access token.
Previously, we would set a cookie at this point using req.session and redirect the user to our dashboard.
With a token API, we generate a token based on the email (acting as a username) and access token (acting as password) when Google calls back to the backend route.
How do we pass this token to the front-end (Angularjs) so that it can make authenticated requests?
Do we need to switch to Google's front-end OAuth APIs?

One way to pass the token to a client-side web application is to put the signed JSON web token into the cookie , which your client-side app can access and use (either appending the token to every GET request or using it in your web socket authentication). Just to be clear, you're no longer using cookies as a reference for server-recorded state, instead you're are simply using them as a storage mechanism that both client and server can access, where you can store your encoded token.
Here's a great example from the generator-angular-fullstack:
In the router, receiving the callback from the google authentication:
.get('/callback', passport.authenticate('google', {
failureRedirect: '/signup',
session: false
}), auth.setTokenCookie);
And the setTokenCookie function:
function setTokenCookie(req, res) {
if (!req.user) return res.json(404, { message: 'Something went wrong, please try again.'});
var token = signToken(req.user._id, req.user.role);
res.cookie('token', JSON.stringify(token));
res.redirect('/');
}
And the signToken function:
function signToken(id) {
return jwt.sign({ _id: id }, config.secrets.session, { expiresInMinutes: 60*5 });
}

Related

Adal-angular app token with secret

I have an app that gets bearer token from Azure ad with adal-angular.
I can ask questions to graph-api to get the data i want with that token.
But now i want to change that data. For that i need an app token from azure AD.
Graph api resource is https://developer.microsoft.com/en-us/graph/docs/api-reference/beta/api/educationschool_update
My app is an React app that uses adal-angular.
My app have an secret to do this.
My question(s) is, can Adal -angular get me this app-token? And if its possible, how can it do that?
below is my config for adal angular. client_secret is what im trying to get to work..
window.authContext = new AuthContext({
tenant: 'xxxxx',
clientId: 'xxxx',
redirectUri: "http://localhost:3000/",
client_secret : 'APP SECRET HERE!?!?!?!?!?!?',
cacheLocation: 'localStorage'
});
this is my method to get token for the logged in person.
aquireToken() {
let header = null;
window.authContext.acquireToken('https://graph.microsoft.com', (error, token) => {
header = {
headers: {
Authorization: 'Bearer ' + token
}
}
});
return header;
}
I think it is not possible from the web client (UI loaded in the browser) because according to Azure AD CORS policy only Authorize endpoint is open to the web clients and you can't send client_secret to the Authorize endpoint. There is no such parameter according to the documentation: https://learn.microsoft.com/en-us/azure/active-directory/develop/v1-protocols-oauth-code
I hope it helps even it came 6 months after asking :)

Angular.js SPA security with ASP.NET MVC and WebApi

I'm building a SPA using Angular.js and ASP.NET and I would like to know what is the best way to secure it.
Here is what I need :
I would like to use MVC framework to hide my application only to logged users. So the first thing that users will do before launching the SPA will be to log into the website using a simple login form.
When the Angular app will be launched, it will communicate with my ApiController using REST requests.
I also want my user to be logged out automatically after 20 minutes of inactivity.
I know that REST is supposed to be stateless... but I can't figure how to implement all I need without sessions...
But on the other side, I want to be able to use my WebAPI with a future mobile application. I will have to use Tokens for the authentication on this application.
What is the best way for me to achieve that kind of authentication?
Thanks for your time!
I developed an entire security layer with the same conditions as yours following those very well explained in this post here.
BTW, the token will expire automatically after 20 minutes because when you create it you will set it's expiration date immediately; every time you're going to make a request, the system will check the token exp date with the current date, refusing your token if the time passed. For example this a tipical oauth server configuration with token and refresh token settings:
internal static OAuthAuthorizationServerOptions GetAuthorizationServerOptions(IComponentContext scope)
{
OAuthAuthorizationServerOptions oAuthServerOptions = new OAuthAuthorizationServerOptions
{
AllowInsecureHttp = true,
ApplicationCanDisplayErrors = true,
TokenEndpointPath = new PathString(Constants.PublicAuth.OAUTH_TOKEN_PATH),
AuthorizeEndpointPath = new PathString(Constants.ExternalAuth.AUTH_ENDPOINT),
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(Constants.PublicAuth.TOKEN_EXPIRATION_IN_MINUTES),
Provider = scope.Resolve<AuthorizationServerProvider>(),
AccessTokenFormat = new CustomJwtFormat(),
RefreshTokenProvider = scope.Resolve<SimpleRefreshTokenProvider>()
};
return oAuthServerOptions;
}
The refresh token is also very useful, but you have to manage the token replacement by yourself; for example in our application we pass every API call through a single service that, if the server responds 401 (unauthorized), it will try to request a new token using the refresh token and then it will try the same call again. Only after the second failure you'll be redirected to the login page.
For example:
function executeCallWithAuth(method, url, payload, params) {
var defer = $q.defer();
debug.logf('{0}: {1}', method.toUpperCase(), url);
$http({ method: method, url: url, data: payload, headers: createHeaders(), params: params }).then(
function(results) { defer.resolve(results); },
function(error) {
if (error.status !== 401) defer.reject(error);
else {
debug.warn(`Call to: ${method}:${url} result in 401, try token refresh...`);
auth.refreshToken().then(
function() {
debug.warn('Token refresh succesfully, retry api call...');
$http({ method: method, url: url, data: payload, headers: createHeaders() }).then(
function(results) { defer.resolve(results); },
function(errors) { defer.reject(errors); });
},
function(tokenError) {
debug.warn('Token refresh rejected, redirect to login.');
$state.go('login');
defer.reject(tokenError);
});
}
});
return defer.promise;
}
and
function createHeaders() {
var headers = {
};
var authData = storage.get('authorizationData');
if (authData) {
headers.Authorization = 'Bearer ' + authData.token;
}
return headers;
}
Using Angular the best way to secure a route is "do not create a route". Basically, you need to load the user profile, and only after that you will create the routes only to the pages he can navigate to. If you don't create the route for a page you don't need to secure that page: Angular will automatically send the user to a 404.
I would secure your WebAPI calls with OAuth2 (you can even use the built in Identity 2.0 provider that comes baked in with it). Keep your WebAPI stateless, use SSL (consider a filter to force it), and use the [Authorize] tags to secure you services. On the MVC side, this will have to maintain state and you will want to have the login form get an OAuth2 token from your WebAPI layer and pass that down into Angular. Set the expiration on this to 20 minutes. You can also use the cookies authentication model here since it will need to be stateful on the MVC side, but all ajax calls made to the WebAPI layer by Angular will need to pass the OAuth2 token as a bearer token in the Authorization request header.

Session and Login User data with Node and AngularJS

I need to know that if my authentication and session management method is right.
I am using session management as when I receive successful auth. from node server. I store user data(without any trace of pass.) in $window.sessionStorage and if user marked rememberMe(checkbox), store data in $window.localStorage too.
Through this I am able to get data in different controllers. Though I read somewhere about session implementation at server(nodeJs) side is also possible. But I am not sure about how to use session along with JSONToken Authentication.
I was using
https://jasonwatmore.com/post/2015/12/09/MEAN-Stack-User-Registration-and-Login-Example.aspx
as a learning example but I could not understand it.
/app/app.js
Why is it in the run() method ?
// add JWT token as default auth header
$http.defaults.headers.common['Authorization'] = 'Bearer ' + $window.jwtToken;
and what is this:
// manually bootstrap angular after the JWT token is retrieved from the server
$(function () {
// get JWT token from server
$.get('/app/token', function (token) {
window.jwtToken = token;
angular.bootstrap(document, ['app']);
});
});
/controllers/app.controller.js
// use session auth to secure the angular app files
router.use('/', function (req, res, next) {
if (req.path !== '/login' && !req.session.token) {
return res.redirect('/login?returnUrl=' + encodeURIComponent('/app' + req.path));
}
next();
});
// make JWT token available to angular app
router.get('/token', function (req, res) {
res.send(req.session.token);
});
// serve angular app files from the '/app' route
router.use('/', express.static('app'));
So using a session server-side with JWT kind of defeats the purpose of using JWT. JWT's are awesome in a number of ways, but one of the ways they are great, is regardless which server intercepts a request, they can verify the user.
If you put it in a session, you have to make sure the client keeps going to the same server as the session is saved in memory on that machine. There are plenty of ways around that, but again it kind of defeats the purpose of a JSON web token.
What I did for my authentication with angular/node/JWT was just passed the JWT back in the header every time, and with my middleware intercepted it with:
req.header.whatever_my_tokens_name_is
The code below set the $http to send on every request the JWT Token to the server.
// add JWT token as default auth header
$http.defaults.headers.common['Authorization'] = 'Bearer ' + $window.jwtToken;
The code below get the token from '/app/token' and store it in LocalStorage. After that, it starts the angular.
// manually bootstrap angular after the JWT token is retrieved from the server
$(function () {
// get JWT token from server
$.get('/app/token', function (token) {
window.jwtToken = token;
angular.bootstrap(document, ['app']);
});
});
Here this is a middleware that check if there are no token stored in req.session.token and requested url is not '/login'. If so, send a redirect to '/login'.
// use session auth to secure the angular app files
router.use('/', function (req, res, next) {
if (req.path !== '/login' && !req.session.token) {
return res.redirect('/login?returnUrl=' + encodeURIComponent('/app' + req.path));
}
next();
});
Finally here, this is a endpoint to the client request the '/token' again from the server.
// make JWT token available to angular app
router.get('/token', function (req, res) {
res.send(req.session.token);
});
Anyway, check the #morgan-g response regarless session-side and JWT.
I hope this helps.

Node.js / Angular.js Admin authorized routes

I'm working on a MEAN application with authentication using JSON web tokens. basically on every request, I am checking to see if user has a valid token. if so they can go through to the route, otherwise they are returned to login page.
I want to make certain routes /admin/etc... only accessible to logged in users who are also admin. I have set up an isAdmin flag in mongo. I am new to nodejs and wondering what is the best way to check this. Do I do it on the angular side in routes? Or can I somehow create permission-based tokens on authentication? For reference, I am following the code from the MEAN Machine book, in particular here -
https://github.com/scotch-io/mean-machine-code/tree/master/17-user-crm
First, authorization decisions must be done on the server side. Doing it on the client side in Angular.js as you suggested is also a good idea, but this is only for the purpose of improving the user's experience, for example not showing the user a link to something they don't have access to.
With JWTs, you can embed claims about the user inside the token, like this:
var jwt = require('jsonwebtoken');
var token = jwt.sign({ role: 'admin' }, 'your_secret');
To map permissions to express routes, you can use connect-roles to build clean and readable authorization middleware functions. Suppose for example your JWT is sent in the HTTP header and you have the following (naive) authorization middleware:
// Naive authentication middleware, just for demonstration
// Assumes you're issuing JWTs somehow and the client is including them in headers
// Like this: Authorization: JWT {token}
app.use(function(req, res, next) {
var token = req.headers.authorization.replace(/^JWT /, '');
jwt.verify(token, 'your_secret', function(err, decoded) {
if(err) {
next(err);
} else {
req.user = decoded;
next();
}
});
})
With that, you can enforce your authorization policy on routes, like this:
var ConnectRoles = require('connect-roles');
var user = new ConnectRoles();
user.use('admin', function(req) {
return req.user && req.user.role === 'admin';
})
app.get('/admin', user.is('admin'), function(req, res, next) {
res.end();
})
Note that there are much better options for issuing & validating JWTs, like express-jwt, or using passport in conjunction with passort-jwt

Some basic questions about JWT (server and client side)

I'm using express.js, passport with jwt strategy and of course jsonwebtoken for node.js.
So, currently, I've managed to implement a server-side logic, which enables users to login and returns the jwt token.
After that, when I do a get request with the corresponding token in the header, it correctly verifies the jwt token and display the info. The code is as follows:
var jwt = require('jsonwebtoken');
function createToken(user) {
return jwt.sign(user, 'shhhhh', {
issuer: "accounts.examplesoft.com"
});
}
var opts = {};
opts.secretOrKey = 'shhhhh';
opts.issuer = "accounts.examplesoft.com";
passport.use(new JwtStrategy(opts, function(jwt_payload, done) {
console.log(jwt_payload);
User.findById(jwt_payload.id, function(err, user) {
if (err) {
return done(err, false);
}
if (user) {
done(null, user);
} else {
done(null, false);
}
});
}));
app.post('/jwt_login', function(req, res) {
User._loginJwt({
email: req.body.email,
password: req.body.password
}, function(err, user) {
if (err) res.json(err);
else res.json(createToken(user));
});
});
app.get('/jwt_test', passport.authenticate('jwt', {
session: false
}), function(req, res) {
res.json(true);
});
Now I'm trying to do a client-side page. I'm using angularjs and there are a lot of jwt libraries for angularjs or rather, client side in general. Now I have a series of questions:
First and foremost, is the server-side implement correctly (from what you can tell by the code above)?
Is it safe if I store the jwt token in localStorage (on client-side)?
Why are there so many libraries available for jwt client side? Isn't it enough to get the token and then call the requests with that token? What else could I do with that token on the client side?
Can't somebody just copy the jwt token from the localStorage and make requests as if they're logged in? Isn't that a security issue?
Thanks for your responses!
The server-side implementation looks fine, though the claims in the token could be expanded. Just always authenticate the token and you're good.
Yes. That's part of why JWT is useful. If the user alters the token, it will not match its signature and will fail authentication.
From what I recall, the client-side stuff is for when you pass data in the payload that is used on the client. You want to be able to authenticate the token on that side as well then, so your front-end doesn't do anything it shouldn't.
a. If you just have a RESTful API that validates requests with the token, you don't have to do anything with the JWT on the front-end besides sending it with requests.
Yes. That's why your token should include an expiration in its claims. Keep in mind, the only way that gets into LocalStorage is if they logged in to begin with.
See here for claims that can be in your token:
http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html#rfc.section.4

Resources