How do you handle navigation in a token-secured web application? - node.js

I have a rather conceptual question, I'm sure it's fairly stupid, but I can't figure it out.
So I am building a simple node.js app to learn, I want to make a web app which is has a set of REST web APIs for everything (including authentication), and then the presentation.
For authentication I am using token-based auth with PassportJS.
So when a user wants to access the site, he'll obtain a token from the authentication API, in turn he'll need to pass this token in a HTTP Header on each request to the app.
My question is, how is this handled in the code? When the app gets the token (for example from a login page which hits the auth API), should it attempt to store it in the local machine (for example LocalStorage, or Cookie) and then on each new page fetch it and use it in a Header? Should each page's javascript attempt to load the token from the local storage automatically? I tried looking for an example, but haven't found a complete one that deals with how you handle navigation when you're depending on sending a header on every single request (that you want authenticated).
Thanks!

Once the user is authenticated return a secure session cookie which will be stored by the user's browser. Now on every request, this cookie will be sent by the browser to your application automatically, which you can check in your backend code (typically controller) to verify the existence of user session.

Related

Making web app with Restful API

I'm making web app using node.js express with Restful API.
And, to use my web app, the user must login. If user doesn't login, he always stays in login page.
But, I heard that restful api doesn't use session or cookie information to maintain user login.
So, I heard that it use JWT. So, I want to use this. But, I saw that it has to compare token information when user access Restful API.
Then, in my case, should the user always have to request token information to the web app server to use my web service? (I mean add token in request header when user request every page)
you can use
HTML Local Storage
When you get JWT token save some value at local storage localStorage.setItem("logenin", "yes");
and check at every page or where you need this infomation localStorage.getItem("logenin");

Authenticating Json Web Token and Redirect After Login

I recently read Cookies vs Tokens for Angularjs and implemented the sign in and authentication piece to allow users to sign in from a sign in page. The app is setup to have the account module (responsible for sign in's, account registration, profile, etc) as a separate page which will redirect to the SPA for the main application.
After successful sign on the token is sent back to the sign in page client as a JWT and the sessionStorage / localStorage values are set via js. Finally the user is redirected (also via js) to the main application. The issue is since I am redirecting via js the header can not be set, which obviously fails the auth in the main app when loading the page (Since my auth middleware is higher than both static and auth api requests). If I attempt to redirect from the server after a form post rather than returning the token via JSON on success, the sessionStorage will not be set via js as described in the blog post.
I've come to a couple of ideas and wanted to get input on which if either is good for best practice.
From the server set a response authenication cookie 'http only' (all our browser requirements allow this) cookie which is read on the next request to the main application. The cookie would then be read by the server and allow the secured static assets to be served. My initial thought was setting a cookie defeats the purpose of using a Authorization header on every request since there is a time the cookie could then be read even if it's removed on the first api request.
Allow the previously mentioned static assets to load without authentication (html, css, application js) and on the first internal API request (which in the application is required almost immediately on load) which will then have access through Angular's $http interceptors to set the request Authorization header. The same interceptor can then redirect to the sign in page if a 401 is sent back.
I thought the second would be a simpler approach due to only needing to move the auth middleware under the static file middleware and then updating the http interceptor in Angular, but thought it might be bad practice to have static files be able to load and then redirect after the fact. Any input is appreciated.
In response to your point 1
... My initial thought was setting a cookie defeats the purpose of using a
Authorization header on every request since there is a time the cookie
could then be read even if it's removed on the first api request.
The use of the authorization header is not mearnt to be mutually exclusive to the use of cookies. The idea is to use it when it best suits the problem like in single page applications and native mobile applications. However since it does depend on some kind of client storage, preferably sessionStorage, it is recommended to even sometimes use cookies for the purpose of storing the token if there are issues with the usage of sessionStorage like in old browsers. Hence as long as you use the cookie for storing the token but NOT for authentication, you have not defeated the purpose. Refer to point 1 in the follow up article
https://auth0.com/blog/2014/01/27/ten-things-you-should-know-about-tokens-and-cookies/
If you are wondering "but if I store the token in the cookie I'm back
to square one". Not really, in this case you are using cookies as a
storage mechanism, not as an authentication mechanism (i.e. the cookie
won't be used by the web framework to authenticate a user, hence no
XSRF attack)

Self Hosted Web API Authentication

I have a self hosted Web API running, which using DotNetOpenAuth to issue authorization tokens. Basically, the project consists of 2 ApiController endpoints (Authorize and Token). I would like to force the client to have to log in to a form, prior to being able to call either endpoint. (Forms Authentication I guess). However, doesn't seem like it works for self hosted Web API projects, so, I am trying to implement something myself.
As of now, when the user calls the Authorize web get method, I render the login page and force them to login. However, I would like to have a mechanism in place so that once the user logs in, I can send a cookie response. I understand that if you write the cookie in the response, the browser will automatically send any relevant cookies upon subsequent requests.
However, my test client uses a HttpWebRequest to call my web api. Do I have to build the mechanism to save the response cookie to a file on the hard disk, and then, read it back, and associate with the HttpWebRequest on subsequent requests? Or , is there something built into the framework which I can leverage (just like how a browser would automatically take care of this for me).
I figured that once I could figure this part out, I could just extend the AuthorizationFilterAttribute, and use that to check the validity of the incoming cookie.
Thanks. Any help or suggestion is appreciated!

passport.js RESTful auth

How does one handle authentication (local and Facebook, for example) using passport.js, through a RESTful API instead of through a web interface?
Specific concerns are handling the passing of data from callbacks to a RESTful response (JSON) vs using a typical res.send({ data: req.data }), setting up an initial /login endpoint which redirects to Facebook (/login cannot be accessed via AJAX, because it is not a JSON response - it is a redirect to Facebook with a callback).
I've found https://github.com/halrobertson/test-restify-passport-facebook, but I'm having trouble understanding it.
Furthermore, how does passport.js store the auth credentials? The server (or is it service?) is backed by MongoDB, and I'd expect credentials (login & salted hash of pw) to be stored there, but I don't know if passport.js has this type of capability.
There are many questions asked here, and it seems that even though the questions are asked in the context of Node and passport.js the real questions are more about workflow than how to do this with a particular technology.
Let's use #Keith example setup, modified a bit for added security:
Web server at https://example.com serves a single page Javascript client app
RESTful web service at https://example.com/api provides server support to rich client app
Server implemented in Node and passport.js.
Server has a database (any kind) with a "users" table.
Username/password and Facebook Connect are offered as authentication options
Rich client makes REST requests into https://example.com/api
There may be other clients (phone apps, for example) that use the web service at https://example.com/api but do not know about the web server at https://example.com.
Note that I'm using secure HTTP. This is in my opinion a must for any service that is available in the open, since sensitive information like passwords and authorization tokens are passing between client and server.
Username/password authentication
Let's look at how plain old authentication works first.
The user connects to https://example.com
The server serves a rich Javascript application which renders the initial page. Somehwere in the page there is a login form.
Many of the sections of this single page app haven't been populated with data due to the user not being logged in. All these sections have an event listener on a "login" event. All this is client side stuff, the server does not know of these events.
User enters his/her login and password and hits the submit button, which triggers a Javascript handler to record the username and password in client side variables. Then this handler triggers the "login" event. Again, this is all client side action, credentials were not sent to the server yet.
The listeners of the "login" event are invoked. Each of these now needs to send one or more requests to the RESTful API at https://example.com/api to obtain the user specific data to render on the page. Every single request they send to the web service will include the username and password, possibly in the form of HTTP Basic authentication, since the service being RESTful isn't allowed to maintain client state from one request to the next. Since the web service is on secure HTTP the password is safely encrypted during transit.
The web service at https://example.com/api receives a bunch of individual requests, each with authentication information. The username and password in each request is checked against the user database and if found correct the requested function executes and data is returned to the client in JSON format. If username and password do not match an error is sent to the client in the form of a 401 HTTP error code.
Instead of forcing clients to send username and password with every request you can have a "get_access_token" function in your RESTful service that takes the username and password and responds with a token, which is some sort of cryptographic hash that is unique and has some expiration date associated with it. These tokens are stored in the database with each user. Then the client sends the access token in subsequent requests. The access token will then be validated against the database instead of the username and password.
Non browser client applications like phone apps do the same as above, they ask user to enter his/her credentials, then send them (or an access token generated from them) with every request to the web service.
The important take away point from this example is that RESTful web services require authentication with every request.
An additional layer of security in this scenario would add client application authorization in addition to the user authentication. For example, if you have the web client, iOS and Android apps all using the web service you may want the server to know which of the three the client of a given request is, regardless of who the authenticated user is. This can enable your web service to restrict certain functions to specific clients. For this you could use API keys and secrets, see this answer for some ideas on that.
Facebook authentication
The workflow above does not work for Facebook connect because the login via Facebook has a third party, Facebook itself. The login procedure requires the user to be redirected to Facebook's website where credentials are entered outside of our control.
So let's see how things change:.
The user connects to https://example.com
The server serves a rich Javascript application which renders the initial page. Somehwere in the page there is a login form that includes a "Login with Facebook" button.
The user clicks the "Login with Facebook" button, which is just a link that redirects to (for example) https://example.com/auth/facebook.
The https://example.com/auth/facebook route is handled by passport.js (see the documentation)
All the user sees is that the page changes and now they are in a Facebook hosted page where they need to login and authorize our web application. This is completely outside of our control.
The user logs in to Facebook and gives permission to our application, so Facebook now redirects back to the callback URL that we configured in the passport.js setup, which following the example in the documentation is https://example.com/auth/facebook/callback
The passport.js handler for the https://example.com/auth/facebook/callback route will invoke the callback function that receives the Facebook access token and some user information from Facebook, including the user's email address.
With the email we can locate the user in our database and store the Facebook access token with it.
The last thing you do in the Facebook callback is to redirect back to the rich client application, but this time we need to pass the username and the access token to the client so that it can use them. This can be done in a number of ways. For example, Javascript variables can be added to the page through a server-side template engine, or else a cookie can be returned with this information. (thanks to #RyanKimber for pointing out the security issues with passing this data in the URL, as I initially suggested).
So now we start the single page app one more time, but the client has the username and the access token.
The client application can trigger the "login" event immediately and let the different parts of the application request the information that they need from the web service.
All the requests sent to https://example.com/api will include the Facebook access token for authentication, or the application's own access token generated from Facebook's token via a "get_access_token" function in the REST API.
The non-browser apps have it a bit more difficult here, because OAuth requires a web browser for logging in. To login from a phone or desktop app you will need to start a browser to do the redirect to Facebook, and even worse, you need a way for the browser to pass the Facebook access token back to the application via some mechanism.
I hope this answers most of the questions. Of course you can replace Facebook with Twitter, Google, or any other OAuth based authentication service.
I'd be interested to know if someone has a simpler way to deal with this.
I greatly appreciate #Miguel's explanation with the complete flow in each cases, but I'd like to add some on the Facebook Authentication part.
Facebook provides a Javascript SDK which you can use to get the access token on client-end directly, which is then passed to the server and used to further pull all the user information from Facebook. So you don't need any re-directs basically.
Moreover, you can use the same API end-point for mobile applications as well. Just use the Android / iOS SDK for Facebook, obtain the Facebook access_token on the client end and pass it to the server.
Regarding the stateless nature as explained, when get_access_token is used to generate a token and passed to the client, this token is also stored on the server. So it's as good as a session token and I believe this makes it stateful ?
Just my 2 cents..
Here is an awesome article I found that can help you authenticate with:
Facebook
Twitter
Google
Local Auth
Easy Node Authentication: Setup and Local

How do I secure REST API calls?

I'm developing the restful web app that using some popular web framework on the backend, say (rails, sinatra, flask, express.js). Ideally, I want to develop client side with Backbone.js. How do I let only my javascript client side interact with those API calls? I don't want those API calls to be public and be called by curl or simply by entering the link on browser.
As a first principle, if your API is consumed by your JS client, you have to assume, that it is public: A simple JS debugger puts an attacker into a position, where he can send a byte-for-byte identical request from a tool of his choice.
That said, if I read your question correctly, this is not, what you want to avoid: What you really don't want to happen is, that your API is consumed (on a regular basis) without your JS client being involved. Here are some ideas on how to if not enforce, then at least encourage using your client:
I am sure, your API has some sort of authentication field (e.g. Hash computed on the client). If not, take a look at This SO question. Make sure you use a salt (or even API key) that is given to your JS client on a session basis (a.o.t. hardcoded). This way, an unauthorized consumer of your API is forced into much more work.
On loading the JS client, remember some HTTP headers (user agent comes to mind) and the IP address and ask for reauthentication if they change, employing blacklists for the usual suspects. This forces an attacker to do his homework more thoroughly again.
On the server side, remember the last few API calls, and before allowing another one, check if business logic allows for the new one right now: This denies an attacker the ability to concentrate many of his sessions into one session with your server: In combination with the other measures, this will make an abuser easy detectable.
I might not have said that with the necessary clarity: I consider it impossible to make it completely impossible for an abuser to consume your service, but you can make it so hard, it might not be worth the hassle.
You should implement some sort of authentication system. One good way to handle this is to define some expected header variables. For example, you can have an auth/login API call that returns a session token. Subsequent calls to your API will expect a session token to be set in an HTTP header variable with a specific name like 'your-api-token'.
Alternatively many systems create access tokens or keys that are expected (like youtube, facebook or twitter) using some sort of api account system. In those cases, your client would have to store these in some manner in the client.
Then it's simply a matter of adding a check for the session into your REST framework and throwing an exception. If at all possible the status code (to be restful) would be a 401 error.
There's an open standard now called "JSON Web Token",
see https://jwt.io/ & https://en.wikipedia.org/wiki/JSON_Web_Token
JSON Web Token (JWT) is a JSON-based open standard (RFC 7519) for
creating tokens that assert some number of claims. For example, a
server could generate a token that has the claim "logged in as admin"
and provide that to a client. The client could then use that token to
prove that they are logged in as admin. The tokens are signed by the
server's key, so the server is able to verify that the token is
legitimate. The tokens are designed to be compact, URL-safe and usable
especially in web browser single sign-on (SSO) context. JWT claims can
be typically used to pass identity of authenticated users between an
identity provider and a service provider, or any other type of claims
as required by business processes.[1][2] The tokens can also be
authenticated and encrypted.[3][4]
Set a SESSION var on the server when the client first loads your index.html (or backbone.js etc.)
Check this var on the server-side on every API call.
P.S. this is not a "security" solution!!! This is just to ease the load on your server so people don't abuse it or "hotlink" your API from other websites and apps.
Excuse me #MarkAmery and Eugene, but that is incorrect.
Your js+html (client) app running in the browser CAN be set up to exclude unauthorized direct calls to the API as follows:
First step: Set up the API to require authentication. The client must first authenticate itself via the server (or some other security server) for example asking the human user to provide the correct password.
Before authentication the calls to the API are not accepted.
During authentication a "token" is returned.
After authentication only API calls with the authentication "token" will be accepted.
Of course at this stage only authorized users who have the password can access the API, although if they are programmers debugging the app, they can access it directly for testing purposes.
Second step: Now set up an extra security API, that is to be called within a short limit of time after the client js+html app was initially requested from the server. This "callback" will tell the server that the client was downloaded successfully. Restrict your REST API calls to work only if the client was requested recently and successfully.
Now in order to use your API they must first download the client and actually run it in a browser. Only after successfully receiving the callback, and then user entry within a short frame of time, will the API accept calls.
So you do not have to worry that this may be an unauthorized user without credentials.
(The title of the question, 'How do I secure REST API calls', and from most of what you say, that is your major concern, and not the literal question of HOW your API is called, but rather BY WHOM, correct?)
Here's what I do:
Secure the API with an HTTP Header with calls such as X-APITOKEN:
Use session variables in PHP. Have a login system in place and save the user token in session variables.
Call JS code with Ajax to PHP and use the session variable with curl to call the API. That way, if the session variable is not set, it won't call and the PHP code contains the Access Token to the API.

Resources