I'm working on a javascript application using a REST API.
Authentication is made with JWT tokens stored in cookies
Right now, this scenario is implemented:
user sign in with credentials. Client calls POST /token to authenticate
server responds with a HTTP-only cookie containing the token.
once authenticated, client makes another request to get all user data (GET /me)
I would like to make this process as fast as possible and reduce the number of server requests as much as possible. I thought about combining /token and /me calls and get token and user data in the same request.
That could be done in different ways :
in the claims of the token, but client won't be able to use it as it's in a HTTP-only cookie.
in another, non HTTP-only, cookie but that will be sent uselessly with every future request, so I don't like this solution
in the response body when server sends the cookie after authentication but I have the feeling that it goes against the REST principles as we send user data from an authentication endpoint.
Is there a way to make this process more simple while respecting standard processes and REST principles?
I personnally use Cookies as a storage, but not in HTTPonly mode. In this case, the simplest is to encode the information you need inside the token.
Are you forced to use HTTP-only cookies? Is it an option for you to change it (in fact, for that you must master the authorization server)?
Another thing : using GET to pass credentials isn't safe as you probably pass your credentials in the URL, which can be fetched from server logs. Prefer POST (and HTTPS of course).
Few pointers about JWT and their storage stategies:
Tokens vs Cookies
Where to store the tokens?
Threats of token theft
Related
I'm new to React and want to securely store the OAuth2 access token to invoke APIs. I have found following options,
Keep it in the local-store/session-store (This can be vulnerable to XSS attacks)
Having a back-end for the React application and store access token in back-end session and keep a session cookie to identify browser session. Then make all the API calls through back-end to add Bearer header.
Encrypt the access token and store it as a cookie. API access will be haven through the back-end where encrypted cookie will be decrypted and added as a Bearer header.
What will be the best solution for this?
I would go for third option
Encrypt the access token and store it as a cookie. API access will be haven through the back-end where encrypted cookie will be decrypted and added as a Bearer header.
Everything related to token we have to store in the client side there is no way around but can make it secure by adding encryption to it to make it more secure but this approach will make developer has to setup encrypt and decrypt algorithim to handle to token
Your second option is best. We also doing this.
Having a back-end for the React application and store access token in back-end session and keep a session cookie to identify browser session. Then make all the API calls through back-end to add Bearer header.
One of the best solution I found recently is oauth2-worker, here it stores tokens in variables inside a worker so that it won't be accessible from the js running on the applications. Also it works as a proxy and we need to make API calls through the worker so that it adds the Authorization header.
I'm exploring JWT and OAuth2 for a Javascript Single-Page-App which will make calls to a backend server-side API. I've come up with a security process that involves using two tokens and gives me the advantage of avoiding the need to have an additional server-side session storage:
The first time the client JS app is loaded up, user sends username/password over SSL to OAuth2 server. The server will set a cookie (normal cookie that is readable by client, without any HttpOnly flag set) that contains a JWT with an OAuth2 access token inside it's claims (along with some other non-confidential data in the JWT claims, ie. user's first/last name, country, role/permission). The server will also set a HttpOnly cookie that will contain the OAuth2 refresh token.
The cookies set by the server will be included on every request from the client automatically (always over SSL), so the server will receive the JWT (see step 3) and both confirm the signature and confirm the OAuth2 access token. The server will also confirm the refresh token. Since the server is checking the access token and refresh token against the OAuth2 database on each request, this gives us the ability to revoke access (which we would not be able to do with the JWT signature alone). We can do a "hard" revoke which revokes both access and refresh token. And we can do a "soft" revoke which just revokes the access token (for instances where perhaps some data that we keep in the JWT claim gets updated, ie. user changes their name or country or role). A soft revoke would be invisible to the client end user (it wouldn't disrupt their logged in status).
In step 2 above, the server will actually look for the JWT in a specific header set by the client (instead of the cookie set by the server). For example, the client JS app will read the JWT from the cookie and then set the JWT in another part of the header. By requring the client to explicitly set a header key/value containing the JWT shows that the client was able to read it's own cookie, thus preventing against XSRF (cross-site request forgery).
The HttpOnly cookie that contains the refresh token ensures we are protected against XSS (ie. some malicious javascript that sneaked its way onto our client). If our JWT was stolen, access still wouldn't be granted because the refresh token was not also seen or stolen by the JS.
With this approach we get all these benefits:
We don't need a server-side session storage. Since we are hitting an OAuth2 server then we can simply just include some extra data in the JWT that we return (non-confidential data). We wouldn't need to re-query/refresh the data in the JWT every time, but perhaps only when the OAuth token is revoked (ie. was revoked when some user data was changed that we include in the JWT's). No need to tackle the storage/scaling requirement that comes with using sessions. The client JS app can use this data like any other app would normally use sessions. For instance I can display a user's name on every "page" in the app. We could also just use websockets, but the JWT is a good backup place for adding some data if we need it.
We are protected against XSRF.
We are protected against XSS.
We can revoke access and also log users out (which is not easily possible with JWT alone).
SSL prevents man-in-the-middle attacks.
The JWT adds a little extra security hurdle for attackers to pass versus just a normal JSON object serialized in the cookie. The attacker would need to get the server-side key for signing JWT's (in addition to OAuth access). The JWT is also a standard, so easier for a trusted developer to work with.
The JWT can be easily passed down to other micro-services sitting behind the OAuth layer to use service-to-service. We can pass it around as "session like" data access to all the services on a request. If a service want's to change something in that data, then they can inform OAuth2 server and it will "soft" revoke the user's current JWT (not really much different from the process with a session storage) and provide a new one.
I haven't exactly seen anyone detail a security process like this yet. Many I see seem to only talk about using JWT with an OAuth2 access token inside and don't elaborate much more. So my question is, does this approach indeed provide the benefits I listed above? If not, what am I missing here and what security hole have I not covered for?
How to send the JWT to a client just after client has authenticated without using Cookies when an html document body is needed to be sent too?
There are docs, blog posts, and tutorials, explaining the cookie-less jwt authentication and leveraging the use of Web Storage API to save the jwt client side. But all of them are trivial examples without sending an html document in http response body upon an authentication which is necessary in some real world applications I can imagine. A cookie can be sent in cookie http response header alongside with an html document in same response's body, I could not still come across a post explaining to do this with a jwt in response instead of a cookie. As I know there is not an API to reach the response headers from javascript in browser if one want to send the jwt in response headers alongside html document in response body.
I have handled your scenario in my project and it can be done in two ways depending on your technology stack you are using and environment constraints, and using OAuth is not mandatory.
Method 1
Send the JWT embedded in the HTML page as a tag. It wont be rendered on the page but can be parsed by you. However, it will be visible in the source window of the browser but it doesnt matter as that would be a protected page and once the next page is rendered, it will not be available.
Method 2
You can send the JWT in a cookie for the first time with a http-only constraint. Handling it over https would bring in extra leverage. Also, like you mentioned, you can delete the cookie.
In case you are using AngularJS on your client side, you have the provision of securing cookies by restricting XHR from the same domain which would avoid the extra task of deleting the cookie.
In fact, #user981375 was mentioning about redirection which can be handled too by Method 1 above. In my case, server provided the redirection URL after successful login however, ajax wouldnt be able to see a 302 header instead would see a 200. So we intercepted that part on server and embedded the token into the 200 response page, i.e. redirected page which is parsed by the client.
I'm in the same boat, I could not figure out how to send JWT token to the client upon successful (or not) social login(s) where redirect was required. Things are simple when when you present user with a login/password and authenticate against your own server via AJAX, but no so simple when you 1) load your login page, 2) do a redirect to OAuth provider, 3) callback to your own server, 4) issue your own JWT token and ... then what?
There is a library out there that provides OAuth support from the client side. You authenticate against Facebook/Google (whatever) get their token back and then you make AJAX request to your own server for token validation. When token is validated by Facebook/Google (whatever) you can then issue your own JWT token with claims and send it as a response (AJAX) to your webpage.
Here is the library and nice article describing how to use it.
HTML documents are usually retrieved from a web application. Web applications are protected by a form of implicit authentication.
Web APIs are usually protected by explicit authentication and the JWT tokens are sent in an HTTP header (Authorization). This is not done automatically by the browser. You have to do this explicitly through JavaScript.
You could of course store the JWT token in a cookie and have it automatically sent to the server on each request.
See also my answer here.
I'm now two weeks into learning and building an AngularJS+ PHPsystem and I'm still struggling with authentication. I've been reading a lot of posts about AngularJSand not one of them seem to consider the security aspect of authentication. I also had an interesting response when I asked about the security of AngularJS storages on another post, and got two great links to Stormpath's blogs which cover areas of security when dealing with tokens.
Most tutorials and examples about AngularJS seem to be taking a JWT approach and sending that token to your REST API via HTTP headers, but given that the token is stored in Javascript this can expose it to multiple attack types. One of them being MITM. To be secure against this type of attack the solution is to set a cookie with HttpOnly and Secure flags. Now the token gets passed on every request, it's not being stored by Javascript and it's secure. However, this raises the question at the point where you authenticate the user: How is this any different than using sessions when you're only dealing with HTTP requests originating from the same server?
When checking if a user has already logged in we usually check if a $_SESSION variable exists, let's say uid. Now on a token based approach we send the token in HTTP headers and read that token, then validate it and get user information. In AngularJSwe then get the successful response and return a promise.
Sessions have the advantage of being handled by the server. They create a session and they handle it's destruction automatically if it still lingers there. When dealing with a token based authentication you have to take care of it's expiration, refreshing and destruction with a scheduled script if the user has not destroyed it himself. This seems like too much work.
The idea of using tokens is to allow for a server to be completely stateless. The server just provides a login service, that upon successful login returns a temporary token, and it immediately forgets the token, it does not store it anywhere (database, memory).
Then the client sends the token at each subsequent request. The token has the property that it's self-validating: it includes the validity, the username and a cryptographic signature.
Such signature proves that the token is valid to the server, even if the server had thrown away the token completely.
This way the server does not have to take care of expiration/destruction of tokens: it can inspect incoming tokens and validate them inspecting only the token (thanks to the signature).
And this is the advantage of JSON Web Tokens: they allow for a completely stateless server that does not have to manage authentication token lifecycle.
I have an MVC site that uses authentication and authorization successfully. I am trying to query an api portion of the site using jquery and the load method. I have attempted to then use
User.Identity.GetUserId()
and this fails, as the request is not authenticated. The page with the ajax request is sucessfully logged in. Is it possible to access its authentication token and pass this with the load request, or do I need to generate a new token in javascript?
EDIT: After some more research, I have found that this line in the WebApiConfig file:
config.SuppressDefaultHostAuthentication();
Is what is disabling the cookie validation for ajax requests. It makes it so only the token method is evaluated. By default MVC uses cookies, and web api uses tokens. I was trying to utilise two different authentication schemes. As the cookie is sent automatically with the ajax requests, the User.Identity is then filled. This answers my original question.
However, this is considered insecure and allows for CRSF attacks. Therefore, token is desirable.
So, reworded, can you use an existing authentication cookie with the /token endpoint to generate an authentication token?
I think you can do the following steps to achieve your goal:
Read authentication cookie on the client using jquery cookies plugin or whatever.
Create an Web API endpoint to handle AJAX authentication which accepts cookie as a body parameter.
Parse authentication cookie, get user information from it and return a token.
Use generated token for subsequent reqeuests.
Ive found a workable solution with the minimum amount of effort.
The ApplicationOAuthProvider is the default provider. It provides an endpoint at /token that you can call with your username and password. In return it provides an authorization cookie, and more importantly a bearer token in the body of the response.
The login flow for the user is unchanged. They visit a log in form, and enter their credentials. This then calls the /token endpoint transparently, returning the response token and cookie. This token can then be saved using javascript to the local or session storage:
localStorage.setItem("token", "value");
This can then be retrieved for any pages loaded in the same browser session. You load this value and pass it in the headers of the ajax request, which then authenticates with the web api.
Use session storage if the user specifies they should not be remembered, otherwise local storage will mean the token is available more often. You do have to check both stores however, and there is a risk the token is invalid from expiration. If this occurs as signalled by an authorization error in the ajax request, you can easily display a message and redirect the user to the sign in page.