Protect API routes in Sails.js with token-based authentication? - javascript

I'm new to Sails.js. I created a new project and a few APIs using the sails generate api [name] command. These new APIs have complete CRUD functionality so I can GET, POST, PUT etc. In order to protect them, I've implemented a standard token-based authentication system that will be used by clients accessing my API. The token is also persisted in the database.
I have two questions:
How do I disable certain actions on specific routes (like enable GET requests on the /user API but not on the /account API but allow POSTS on the /account API for example)
I want the client to send me back the generated Access Token for every post-authentication request. When they do, how do I intercept the request and check if the token exists in the database before allowing access to the requested route?
Thank you.

You will need to create policies to prevent non-authenticated user to perform some requests. I consider here that GET /user and GET /account will be routed to a find function. And POST /account routed to a create function.
In config/policies.js :
module.exports.policies = {
'UserController': {
'create': 'isAuth',
'find': true
},
'AccountController': {
'create': 'isAuth',
'find': true
}
}
You will need to add a isAuth.js policy file in api/policies
To authenticate user in Sails, I use (as many others) passportjs. You will define auth strategies. It is a powerful tool and will allow you to create custom auth strategies or use OAuth2 protocol if you need (if you use token you should use it).
Sails does exactly intercept every requests and execute the policy you configured for the routed action.
You will be able to find some documentation on the Internet on Sails, Policies, Passport, Oauth2.
Hope I have helped you.

I've gone ahead and created a guide for you here: https://github.com/carlospliego/sails-token-auth-setup

Related

NextJS auth with an external server

I'm working with auth in Nextjs, I'm wondering what is the best strategy to handle authentication in NextJS ?
Here my services structure :
If I understand well I have to handle the server side rendering in NextJS, so I understand I have to put cookies from my external server to my NextJS client, then handle the server side rendering checkings. To do that I assume I have to create connection between the NextJS server and the other services. Before dive more deeper in the subject I would discuss with you about the possibilities available to me. It seems the NextJS auth is a subject in plain development.
Any hint would be great,
Thanks
I've recently added an example with cookie auth which explains what you are trying to do on the frontend.
For the backend, optimally you'll have your API in an external server, apart from the server you use for rendering your Next.js app. This API will handle the database and the token creation business. Then the basics of the authentication are like this:
The client POST a request with username and password to the server.
The server gets the request and generate a token based on the data received.
If everything went okay validating the data, the server responds with the token, e.g., { token: "secrettoken" }.
The client receives the token and saves it in a cookie. Optionally you redirect the user to the /dashboard or /profile if everything is okay.
The client, on restricted pages, will check if the cookie exists and optionally validate that against the server, you do this last part in getInitialProps. If the cookie validation fails you redirect the user away.
I've created a small library to abstract this logic.
So in the end, your Next.js app shouldn't know what's happening in the server, it only should receive the token, save it, validate it, and redirect the user if something is wrong.
How you want to handle the token creation, on the external server, is up to you.
Check out this thread. There are several examples of how to do Authentication with JWT, OAuth etc throughout the thread. You'll see that the examples are utilizing getInitialProps and there are several examples utilizing cookies throughout to extract the Authentication tokens.
You'll have to write a custom server.js file using express.js to serve the tokens through your route requests. I'm assuming by "external server" you mean some third party Authenticator using OAuth or OpenId protocols to retrieve tokens. If so, you're right to say that you'll need to request the tokens (or Authentication mechanism) from those external services and then decide how you're going to utilize them in your own client. You'll probably be using getInitialProps to do what you need to do with your Authentication tokens in the client once you are rendering to the browser.
More examples of Authentication here -- one for firebase and another for Apollo.
Just to add to the answers if you want to use Auth0 specifically. In the interview on http://www.fullstackradio.com/112 around the 1:06 min mark Guillermo Rauch mentioned that if he were to implement authentication all over again he would use Auth0, so I created a minimal repo using Auth0 and Nextjs with Serverless functions.
Like #jolvera suggested there is an API in an external server, apart from the server used for rendering the Next.js app. This API is located in ./auth/auth.js. It handles the token creation business, and could be extended to handle the database.
The HOC component in ./utils/withAuth.js calls the auth.js lambda for the user information, and is only able to retrieve it if the client side is authorized. Otherwise the user information is undefined. Additionally there is an event listener similar to the one in with-cookie-auth which syncs logouts across tabs.
Also one other note, don't get confused with the Nextjs example on Auth0's blog. That example is extending the Nextjs server, and isn't the solution you want if you are deploying Next to serverless. It doesn't have the separation of concerns with page routing and authentication.

Handling client-side authorization with Firebase

I'm building a client that uses Firebase, the Firebase JavaScript SDK, the Firebase Authentication service, and the Real Time Database for persistence.
Following a number of different sources, I have the authentication piece working well, but I'm finding limited options for authorization for what I'd consider an efficient solution.
What I want to do is attach a single key/value of role: 'admin' to the user's auth record so that I can conduct both authentication and authorization with only one client-based call to the Firebase backend.
I've read about attaching custom claims to the Firebase Authentication record, but I've only seen folks using the Firebase Admin library (backend) to both set the token and parse the token. I'm trying to not add additional calls through Firebase functions or a custom Express server, if I can help it.
Adding a separate User profile record to the RTDB is easy, and I can store the auth data there. However, this will always require a simultaneous call for Authentication and Authorization, which, again, seems very inefficient and excludes secure offline use of the client (if roles change on the RTDB).
It also seems inefficient to make a client-based call for authentication, then fire a mandatory second client-based call to retrieve authorization data from a Firebase function (or any other backend service) that can implement the Firebase admin library.
Main question: Is there a way with JavaScript to achieve the goal of setting/retrieving both authentication and authorization data from the Firebase Authentication service with a single request to the backend and processing on the client?
The two options you've given are the idiomatic approaches for custom roles.
If you embed the role into the user's token as a custom claim, you'll get it in the authentication request. Since this is an operation that elevates permissions, it should be done in a trusted environment, such as a server you control, Cloud Functions, or (if infrequent enough) from your development machine.
If you don't want to do that, and want to store it in the database, you'll need an extra request. The overhead of that call is usually not a performance problem.
A combination of the two is also possible: identify the initial "system administrator" UID manually, and then use that in your database security rules to allow the to grant additional rights to other users. But that will also have the roles in the database.
Instead of finding reasons to not use these idiomatic approaches, I recommend implementing one and seeing if your concerns surface in practice.

Multiple Spring Security configurations for REST via BasicAuth vs. Session with CSRF

In am working on a Spring Boot (1.3.2) application which just serves Spring MVC REST controllers that are consumed by a JavaScript single page app (deployed standalone, not inside the boot jar). The setup uses Spring Security, Spring Session and has CSRF protection enabled.
This works as expected for the JavaScript client. A login is done by a GET call with Basic Auth provided, the backend creates a session, returns a cookie and also provides the CSRF token in the response according to this blog post at https://spring.io/guides/tutorials/spring-security-and-angular-js/ (except that the custom filter is way more behind in the chain to obtain the correct token after the SessionManagementFilter - which is not that relevant for this question I think).
Until here, everything works as intended pretty elegantly without any workarounds.
Now we also want to expose some of the interfaces for mobile/cli clients. These clients should be able to access a subset of the interfaces via Basic Auth. So the goal is to allow non-readonly calls (POST, PUT, DELETE) for these clients by just providing the credentials via Basic Auth. As they provide the credentials in their request, it is not neccessary for them to provide a CSRF token.
So my first idea was to look for some way to conditionally skip some filters (the csrf) if there was a successful authentication by the provided Basic Auth. It seems that the existing filters are not meant to be used in that way and this would also somehow violate the concept of Spring Security.
I then thought to have found a solution by using the concept explained in the Spring Security docs (http://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#multiple-httpsecurity) that uses separate WebSecurityConfigurerAdapters as also described in Spring Boot web app w/ both session + CSRF & stateless Basic Auth w/o CSRF or
How can I configure spring security for multiple servlets?
So currently I have two WebSecurityConfigurerAdapters with different Orders and disjunct request matchers, both overriding configure(AuthenticationManagerBuilder auth) and configure(HttpSecurity http). I therefore aliased the relevant REST controllers by using #RequestMapping({"/things", "/aliased/things"}) to be able to get separate security filter chains.
This works in a way that depending on the Path ("things" or "aliased/things") the according filter chain is used. But somehow this setup is still corrupt as I now can do a "login" on the regular path, which creates a session and with this session, I now can also call one of the second filter chain's path which now results in a correct authentication (probably due to the SecurityContextPersistenceFilter) which authenticates me and allows non CSRF-protected calls to the interfaces on the chain which should be used by the mobile clients only.
This seems not to be the way to handle such a case. I am interested in finding hints how to handle that requirement - which in my opinion should be some common use case. Probably I was running way to far in the wrong direction with my experiments.

Moving from Session-based token mechanism to OAuth 2.0 mechanism

I own a Play Framework application acting acting as a backend server providing a set of REST APIs.
At client side, I own an AngularJS application that calls APIs from backend-server through AJAX.
Currently, I make use of a solution based on Session-token mechanism.
Meaning that each time a user logs in successfully, a cookie is retrieved at client side containing an authentication token.
At each request then, the cookie value (the auth token) providing by the client request is extracted on the server and if valid, the request is made.
Now I want to use OAuth 2.0. Reasons are? :
It's a great standard way to secure API, avoiding the use of a datastore (Memcached) to keep auth tokens at server side, as I'm currently providing.
I want to provide a better secure than a sole cookie, by providing some client_secret and nonces to avoid some replay attacks etc...
I want to restrict the amount of clients capable to call even public REST API I provide, meaning API that allows anonymous call, like listing a list of items for instance.
The point is that I don't involve a third party, since all protected resources are on my own.
I came across this article explaining how to secure internal REST API with OAuth 2.0 implementing a 2-legged instead of a 3-legged as usual.
However, I can't figure out how the Client Credentials flow could authenticate a specific user, when calling for a REST API that needs to have a user authenticated.
Indeed, Client Credentials flow seems to be based on a global client_id, client_secret keys (global to the app, so in my case to my Javascript app), and therefore not enough specific to target a specific user and controller its specific rights.
Any help would be great.
Seems like you should use "Resource Owner Password Credentials Grant" (https://www.rfc-editor.org/rfc/rfc6749#section-4.3). It is dead simple - put client ID/secret in Authorization header and put user name/password in query variables. Here is an example from the RFC:
POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
grant_type=password&username=johndoe&password=A3ddj3w
Server side you can check for both validity of the client (your javascript app) as well as the user. Just remember that it is impossible to protect the client credentials as it will be embedded in your (downloadable) JavaScript code. The user name/password is entered directly by the end user.

Performance of Stateless Authentication in SPA and SSO (Single Sign On)

If I have a SPA (Single Page Application - developed with BackboneJS) and want to have a stateless RESTful backend API for its data. I like how 3rd party single sign on makes things so easy for the user, thus will like it use it.
But I understand in a stateless environment like this, authentication is done on every request? If so, if I am using a 3rd party SSO, eg. GitHub, won't I need to goto GitHub to authenticate the user everytime? Whats the best practice for such situations? I believe its a very common use case? - I allow the user to login via Google/GitHub or something, then get data from some stateless REST API
Disclaimer :)
Having implemented such a thing for my product, and sharing many of your concerns and tech (especially SPA with Backbone using a 100% stateless REST backend) I can tell you what are my thoughs about this, making clear that this doesn't want to be "the answer" but rather a conversation starter to learn from the resulting discussion, as I think I too have quite a bit to learn on the topic.
First of all, I think you should go 100% stateless. And by 100%, I mean 100% :) Not only your API layer should be stateless, but the whole application (except client, of course). Moving sessions on a different layer (eg. redis) just moves the problem a bit, but doesn't solve it. Everything (especially scaling) will be so much easier, and you will thank yourself about this decision later on.
So, yes, you need to have authentication on every request. But this doesn't mean that you have to hit the auth provider every time. One of the things that I learned is that allowing an user to authenticate via FB/GitHub/Whatever (from now on, remote service) is just a mean to ease the pain of signup/signin, nothing else. You still have to grow your personal database of users. Of course, each user will be associated to a "remote" users, but soon after the authentication has been performed, the app should reference "your" user, and not the "remote" user (eg. GitHub user).
Implementation
Here's what I've implemented:
My API methods always need an authentication token. The auth token is a hash that represent an user of my system, so that when I call POST /api/board?name=[a_name]&auth=[my_token], I know who's calling, can check permissions and can associate the newly created entity board to the correct user.
The said token has nothing to do with remote services' tokens. The logic they are computed from is specific to my app. But it maps an user of mine, that is also mapped to a remote user, so no information is lost in case it's needed.
Here's how I authenticate the user via a remote service. I implement the remote authentication as specified in the service documentation. Usually it is OAuth or OAuth-like, this means that in the end I get an authToken that represent the remote user. This token has 2 purposes:
I can use it to call API methods on the remote service acting as the user
I have the guarantee that the user is who it says it is, at least by the means of the remote service
As soon as your user authenticated itself with the remote service, you load or create the matching user in your system. If the user with remote_id: GitHub_abc123 is not present in your system, you create it, otherwise you load it. Let's say this user has id: MyApp_def456. You create also an authToken with your own logic that will represent the user MyApp_def456 and pass it to the client (cookies are ok!!)
Back to point 1 :)
Notes
The authentication is performed at every request and this means that you deal with hashes and crypto functions, that by definitions are slow. Now, if you use bcrypt with 20 iterations, this will kill your app. I use it to store the passwords of the users when they log in, but then use a less heavy algorithm for the authToken (I personally use an hash comparable to SHA-256). This tokens can be short lived (let's say less than the average time to crack them) and are fairly easy to compute on a server machine. There's not an exact answer here. Try different approaches, measure and decide. What I am sure about, instead, is that I prefer to have this kind of problems than session problems. If I need to compute more hashes, or faster, I add CPU power. With sessions and a clustered environment, you have memory issues, load balancing and sticky sessions problems, or other moving pieces (redis).
Obiouvsly, HTTPS is absolutely mandatory because authToken is always passed as a parameter.
The way I would implement it is by introducing a proxy between the client (Backbone) and the RESTful webserver. The proxy manages authentication of users in conjunction with SSO. Therefore no need to change the api and/or client/webserver. Here a quick demo:
var http = require('http'),
httpProxy = require('http-proxy'),
express = require('express');
var proxy = new httpProxy.RoutingProxy();
var app = express();
function ensureAuthenticated(req, res, next) {
if (isLoggedIn) { return next(); }
res.redirect('/');
}
// This should be your (RESTful) webserver
http.createServer(function (req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write('request successfully proxied!' + '\n' + JSON.stringify(req.headers, true, 2));
res.end();
}).listen(9000);
var isLoggedIn = false;
app.get('/', function(req, res){
console.log(isLoggedIn)
res.send('Logged in? ' + isLoggedIn);
});
app.get('/login', function(req, res){
isLoggedIn = true;
res.redirect('/');
});
app.get('/logout', function(req, res){
isLoggedIn = false;
res.redirect('/');
});
app.all('/api/*', ensureAuthenticated, function(req, res) {
return proxy.proxyRequest(req, res, {
host: 'localhost',
port: 9000
});
});
app.listen(8000);
The first time you visit the page, you're logged out and any call to /api/something gets redirected to /. When you're logged (visit the /login page) all requests to /api/* are routed through the proxy to the webserver listening on port 9000.
In particular, when you set app.all('/*', ...) all the calls to your API server stay the same but are augmented with an authentication layer. The concept is trivial to extend with oauth (have a look at passportjs if you are using node).
You could adopt the approach used in Facebook's JavaScript SDK.
This documentation page provides the quick-start to login vith Facebook for web. Not very deep, but explains the basic of how to use their approach. Does not mention the possibility of signature, however.
When registering Facebook logon for your app, you get an app secret from the application dashboard on Facebook.
When the user have logged on to your app via Facebook, your JavaScript gets an authentication object. This object contains a signature. (If you set it up correct in the dashboard.)
You can supply this authentication object with the client call to your RESTful server, and on the server check that the signature is correct. This way you know that the user was authenticated by facebook, is this user, and was authenticated for your application.
This documentation page describes how to use the signed authentication. Do not be intimidated by the "games" in the headline, it works perfectly fine for any web app.
Instead of allowing only Facebook for SSO, you can implement something in the same spirit as the FB login, using other OAUTH providers.
Use the solution suggested by danielepolencic, but modify it such that instead of a proxy in the same node.js instance you have another server for logins. This service does the OAUTH check with the provider, and maintains session with the client. It emits a signed token to the client, with a short time-to-live. The client must ask for a new token before the time-to-live ends.
You then implement a client-side JavaScript with functionality similar to Facebook JavaScript SDK for the login to be used by your application. This function can either poll for new tokens, or retrieve a new token on request, whatever is most efficient for the scenario.
The client supplies this token to the RESTful API on each request, and the server checks the signature. Just as for the Facebook SSO.
There still is a session, but it can be maintained visavis completely different machines. This service can be scaled independently of the servers with your RESTful api.
However, bear in mind that this approach can be susceptible to man-in-the-middle attacks and replay attacks. Probably unwise to use without https.

Categories