We are implementing a sample application using Kong API gateway with JWT authentication plugin.
As refer in this thread, there are two ways to store JWT in the browser. Web storage or cookies. But web storage (i.e. session storage and local storage) can be vulnerable to cross-site scripting attack(XSS). So other option is cookie. (Though CSRF should be taken care off)
I have two questions,
If we use web storage to store JWT then is there any way to stop XSS. If yes then how it will work if the same page is open in the new tab or reload the same page ?
Using cookie: We are able to send the cookies in the request. But KONG is authenticating the end point URL only if the JWT is set on headers (Authorisation: Bearer token) and not authenticating using cookies. Is there any way to verify JWT which is set in cookies using KONG API Gateway ?
There is nothing wrong about storing JWT in webStorage, unless you store sensitive data in your JWT (but you should never ever do that, since you can decode it easily). The point is that your token shares a secret, that only your servers knows (that's what makes it secure), you should just put an expiration time to make it a lot safer.
And no, you cannot pass a JWT token in cookies, it's only in headers (here Authorization), I don't know about KONG API, but they should not allow that !
(ref about JWT is here)
In order to add to #antoine2vey answer,
It looks like your on page application is being served from a protected API in Kong at the "/" (slash) resource. I would suggest that you would be able to get the page content from an unprotected "/" (slash) resource and then run javascript code would have access to the cookie and would be able to perform the request to the protected resource passing the JWT token in the header where Kong would be able to validate for you.
Does this make sense?
Cookie based authentication is implemented. https://github.com/Kong/kong/pull/2973
Related
Note that I'm quite new with OAuth2 and OpenID Connect so I may be a little bit confused. AFAIK, the recommanded authentication flow with OAuth2 in 2021 is Authorization Code Flow. I have already read the RFC 6749.
I have initialized a project using JHipster (v6.10.5, not the v7) with this configuration:
Which type of application would you like to create? Monolithic application (recommended for simple projects)
Which type of authentication would you like to use? OAuth 2.0 / OIDC Authentication (stateful, works with Keycloak and Okta)
Which Framework would you like to use for the client? React (i.e. a SPA application)
I'm wondering why is the JHipster's implementation stateful? (i.e. using HTTP session cookie JSESSIONID ; access token and refresh token are stored on the backend-side and NOT on the browser-side).
Why don't they make the browser acting as an OAuth 2.0 client to perform the authentication and storing the access token and the refresh token on the browser-side?
I don't find any explanation on the JHispter security page.
Beside, this blog mentions a schema that explains the OIDC Authorization Code Flow with a Public Client / SPA.
To complete Matt Raible comment, from OAuth 2.0 for Browser-Based Apps - draft-ietf-oauth-browser-based-apps-07 and ยง6.1. Browser-Based Apps that Can Share Data with the Resource Server:
[...]
An additional concern with handling access tokens in a browser is that as of the date of this publication, there is no secure storage mechanism where JavaScript code can keep the access token to be later used in an API request. Using an OAuth flow results in the JavaScript code getting an access token, needing to store it somewhere, and then retrieve it to make an API request.
Instead, a more secure design is to use an HTTP-only cookie between the JavaScript application and API so that the JavaScript code can't access the cookie value itself. Additionally, the SameSite cookie attribute can be used to prevent CSRF attacks, or alternatively, the application and API could be written to use anti-CSRF tokens.
[...]
However, I think the use of HTTP-session and OAuth2 token on the backend-side may complexify the management/implementation of some issues as we have to handle different timeouts:
idle timeout for HTTP session between the browser and the backend
expiration timeout or maximum lifetime expiration for the refresh token that is stored on the backend side
...
I'm now wondering how to provide a user-friendly experience, when some borderline cases happen. E.g: when the refresh token has expired on the backend-side but the end-user is still connected as the HTTP session between the browser and the backend is still valid.
I wrote an API that uses JWT to authenticate the incoming requests.
I connected an ASP.NET Core application to this API. When the users login to the application, it asks the api if the credentials are goods, and if they are the api sends back a JWT token to the application.
This application finally stores the JWT to an httpOnly cookie on the client.
Now, I want to use the "User.IsAuthenticated" feature to displays the name of the actual user if he possesses a JWT cookie.
To do so, I wrote a JWTManager which analyze each requests of the application and if the user possesses a JWT cookie, the Manager will authenticates the user with HttpContext.SignInAsync by decoding the JWT, verifying his authenticity from the api then reading all the claims it contains before adding it to the User Session.
Tldr, I discuss to the api with jwt but I use cookie sessions on the application, sessions that I ironically create from jwt too.
My question is, do I need to keep sessions ?
Basically, I implemented the cookie session to use the [Authorize] annotation. But because the api already uses it, I can simply verify if the api returns unauthorized to stop the user from accessing the content he isn't authorized to use.
To display the name, I can avoid the User.Identity.IsAuthenticated and simply look for his JWT, verify if its authentic from the api then displays his name from the JWT. If he hasn't a JWT, I can display "Sign in" instead of his name.
What is the optimal way to use JWT ?
I choose it to reduce the calls to database from the api and to make the cross applications easier to use. And avoiding session will also reduce the memory used by the server to store them.
But is it worth it ? I'll ask the api if the JWT is authentic at each request from the client, then decode the JWT to at least write the username on the navigation bar to each requests (yes I can use cache and ajax to avoid reloading the navbar at each request, but I still need to verify if the user has access to the content).
Is it more efficient than just use a session with several roles and [Authorize] my content ?
Or finally my mixed use of both feature is efficient ? (Authenticate and discuss with the api from jwt will using session on the application)
According to this (on youtube) conference, we should not use Cookie authentication for Web Api, because in case there are multiple servers on the same domain, there is a possibility for CSRF attack.
another source
He says the following: "we should instead use JWT Bearer tokens"
How exactly using JWT token authentication solves this problem?
EDIT
This sheds some more light on what is going on.
As i understand there are two ways of mitigating CSRF:
Put tokens into Authentication header instead of cookie and store tokens in localStorage. This way they do not get attached if sent by some rogue form as described in the article above. JWT tokens are put into Authentication header?
Another way, as i understand, works by using hidden input field to add antiforgery token. This can be turned on easily in Razor and is supported in Angular. But what about React? This way we can stick with standart Cookie authentication for Web Api? Can we do it in React? Is there any example?
But what about sharing domains, as described in article above? Is there any risk of another app on the shared domain to obtain authentication token or cookie?
I am wondering, if JWT should be attached to the header of my request manually, how can I use JWT to authenticate the users of my ASP.Net Core website?
In other words, how can I tell my browser to attach the token in the header when sending the request to my server? Let us say the user of my website got this token from one of my website's API.
Or is JWT usable only for WebAPI (where I can manually build the request)?
There are different ways to use JWT tokens. Since JWT is just a token format, it does imply the method used for authentication.
However, JWTs are mainly used for Bearer authentication scheme, which requires adding a custom header to each request. Single page applications (SPAs) that create requests in JavaScript on the client to access API endpoints can do that which is why Bearer+JWT is used a lot in SPAs. SPAs also benefit from the embedded JSON format since they can read expiration dates and other information (claims embedded in the token, ID token contents obtained via OpenID Connect etc.).
For "traditional" server-rendered views and links, using JWTs is hard since they'd have to be set as cookie or made part of the URL (practically impossible because of URL length restrictions). ASP.NET Core 2.0 does not contain any JWT-based cookie logic but it is possible to create a custom implementation using JWTs as cookies. See this GitHub project and related blog post for a sample implementation. Note that the only benefit of using JWTs in cookie authentication is that the server doesn't have to persist cookie information and share cookies across multiple instances.
To sum up the current state:
Prefer default cookie authentication when you use server-side rendering and links to avoid creating custom cookie implementations.
Prefer JWT bearer authentication if you have single page applications (SPAs) apps that build requests in javascript/typescript on the client.
I'm building an Angular app with an API backend. On a combination of pieces of advice, I built the API with a flavor of token authentication. The flow is roughly as follows:
POST to login endpoint with credentials
Validate credentials and authorization, then generate a new token
Return token to client
Client uses token via HTTP Basic to access API resources
This is all working well. The problem arises in creating a session based on this token. I don't believe I should simply hold the token on the client in a cookie, but I do need a session to persist between page refreshes, etc. My Angular app is stateless and completely populated via API calls.
I'm looking for a recommendation as to hanging on to this token on the client. I feel there's danger in holding the token in a cookie because the cookie could be stolen and simply used to authenticate as someone else, but perhaps this is incorrect.
Thanks in advance for your assistance!
The only known way for me to identify a user is to use some token on the client.
HTTP is stateless and can't know which request is coming from which user (browser). You can't identify the user by his ip address (many users are behind a router and share a connection). You could try browser fingerprinting, it can work on some browsers but not on all.
I would recommend using a cookie to store this token on the client.
They are send to the server on every request and you can do some protection to keep them from getting stolen.
To protect this cookie from man in the middle attacks you need to use an encrypted connection over HTTPS to the server.
Set the following attributes on the cookie:
HTTPOnly: cookie can't be accessed by javascript (XSS protection)
Secure: cookie will only be send over https
Path: cookie will only be send on specified path e.g. /login
I would also define an expiration date on the cookie, so the cookie is invalid in like 2 days or something.
But you are right. If this token gets stolen someone else can login as this user.
Since its an Angular app, I'd assume all authenticated methods will only be served to ajax requests (you can tell your server to only respond to ajax) in which case CORS will help you.
The only way to be completely secure is HTTPS, however this method is probably more secure than you think. Read up on CORS a bit for more info, but essentially the idea is that servers will only respond to ajax requests coming from html pages that were served by that same domain.
Pre-flight OPTIONS requests are often sent to verify this. The browser sends an OPTIONS request with an Origin header (the origin of the page) before the actual request. If the origin matches the domain of the server receiving it, the subsequent request is allowed. Otherwise, it violates the Same Origin Policy and will be rejected.
This prevents someone from sniffing out the token and sending a request with the token from a page that your server didn't serve (like something running on the hackers local machine).
If you are doing credit card transactions or anything super secure, you should use HTTPS though.
http://en.wikipedia.org/wiki/Cross-origin_resource_sharing