Unable to to access Generic Views with JWT authentication - reactjs

I'm at a loss - I have a django backend and react frontend. On the frontend, I have a login page that sets a JWT token, and I use that token to query data from the django backend. This all works perfectly.
But I also have direct views to these APIs via something simple as http://localhost:8000/tables/data which will just show me a default django view of these tables (ie: a paginated "select * from data" call) ... and hooked in through a genericListAPIView.
Now, as I said, everything works fine when feeding it via a curl command (or postman, or whatnot). I get the JWT token, set it the Authorization access in the subsequent call to the API, and get the data back and do something with in in React.
What I can't seem to figure out is how to hoo that same JWT token when calling trying to access the generic view. When I browse to it, I get
HTTP 401 Unauthorized
Allow: GET, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept
WWW-Authenticate: JWT realm="api"
{
"detail": "Authentication credentials were not provided."
}
Which I guess make sense since I'm not going through any React authentication. Yet, it's the same server. Should be same authentication (and in fact the login accounts are being managed by django).
I've googled, and read (and tried) a bunch of different things and can't seem to wrap my head around what I am doing wrong. Any help, or any direction, would be much appreciated.

When you make a request from a browser, you can only rely on session cookies. The browser is not able to automatically add an access token to the request. In order to make a request with an access token, you have to make it using Javascript.

Related

IdentityServer API unauthorized if hosted in IIS

I added additional API to the Duende IdentityServer 6.2 as described here. Then I tried to access it from a sample App, using typed httpClient using their own library called AccessTokenManagement (aka Identity.Model) pretty much following their simple example. I use Authorization Code flow, everything pretty much simple and default.
It works well until both server and client are on the same dev machine under localhost. As soon as I publish IdentityServer to IIS, the API stops to work, while the rest still works well (I can be authenticated, and I see in the Fiddler that token exchanges work normally).
The call to API consists from two calls:
Calling to /connect/token using refresh token. Server returns access token.
Calling my endpoint using this new access token.
The flow fails on the step 1. Call to /connect/token is already unauthorized and I can't understand why. The "good" and "bad" calls looks the same, I cannot see any differences. Previous call moment ago to /connect/userinfo consists of the same two steps and it works. Logs on both server and client give no clues.
No reverse proxies, just good plain simple URI. Automatic key management is enabled and the keys are in the SQL table, common for dev and published server. Asp.Net Core Data Protection is enabled and keys are also common.
Relevant parts of logs are below. I noticed that "No endpoint entry found for request path" is specific to IdentityServer and it doesn't actually mean that endpoint was not found. It was found but not processed. I also noticed reacher response headers from bad request and log entry about "Cookie signed-in" in good request but not sure what does it mean and whether it's relevant.
I'm running out of ideas.
Bad response from IIS while trying to get new Access Token:
Proper response while developing:
///////Relevant part of log for BAD request
|Duende.AccessTokenManagement.OpenIdConnect.UserAccessAccessTokenManagementService|Token for user test#test.com needs refreshing.
|Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler|AuthenticationScheme: cookie was successfully authenticated.
|Duende.AccessTokenManagement.OpenIdConnect.UserTokenEndpointService|refresh token request to: https://auth.mysite.org/connect/token
|Duende.AccessTokenManagement.OpenIdConnect.UserAccessAccessTokenManagementService|Error refreshing access token. Error = Unauthorized
|System.Net.Http.HttpClient.IdsService.ClientHandler|Sending HTTP request POST https://auth.mysite.org/mycontroller/myaction
|System.Net.Http.HttpClient.IdsService.ClientHandler|Received HTTP response headers after 117.7278ms - 401
///////Same part of GOOD request
|Duende.AccessTokenManagement.OpenIdConnect.UserAccessAccessTokenManagementService|Token for user test#test.com needs refreshing.
|Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler|AuthenticationScheme: Cookies was successfully authenticated.
|Duende.AccessTokenManagement.OpenIdConnect.UserTokenEndpointService|refresh token request to: https://localhost:5001/connect/token
|Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler|AuthenticationScheme: Cookies signed in.
|System.Net.Http.HttpClient.IdsService.ClientHandler|Sending HTTP request POST https://localhost:5001/mycontroller/myaction
|System.Net.Http.HttpClient.IdsService.ClientHandler|Received HTTP response headers after 1994.9611ms - 200
///////Server log during BAD request
Duende.IdentityServer.Hosting.EndpointRouter No endpoint entry found for request path: "/mycontroller/myaction"
Duende.IdentityServer.Hosting.LocalApiAuthentication.LocalApiAuthenticationHandler HandleAuthenticateAsync called
Duende.IdentityServer.Hosting.LocalApiAuthentication.LocalApiAuthenticationHandler AuthenticationScheme: "IdentityServerAccessToken" was not authenticated.
Duende.IdentityServer.Hosting.LocalApiAuthentication.LocalApiAuthenticationHandler AuthenticationScheme: "IdentityServerAccessToken" was challenged.
Okay, found it. Thankfully, looked at Fiddler's WebView and had seen familiar picture!
Then, found this topic. The solution was disabling Basic authentication in IIS settings. Access token request has basic authentication header and it seems like IIS intercepts it. Still a bit unclear why other parts of flow worked.

Using HTTPOnly Cookie Returned from API in React app

I am working on my first React application which consumes a REST API. Certain information within the API isn't accessible unless authorized by logging in, and the API returns an HTTPOnly cookie as a response upon a successful POST request to the login endpoint; I'm using axios, to accomplish this. It's possible to view the cookie within the network tab of the browser and it also successfully logged to the console, but I'm unsure of how I can actually store the information returned from the API within my react app. The cookie vanishes from the browser when I leave the page after logging in. Is there a way I can implement this cookie into the React App's memory/state so it can be sent and used upon future requests in the application? I've scoured for a few days and seen various methods to access a returned JWT, but most of them include using LocalStorage which isn't secure or are from deprecated tutorials many years ago. After logging in, the JWT returned from the API will need to be sent back upon future requests, which will also be made using axios.
All help is much appreciated.
You can configure the expiry of the HttpOnly cookie. It sounds like your server is currently storing the JWTs in HttpOnly session cookies. If you are using Chrome, you can confirm this by looking at the "Expires / Max-Age" column in the Application tab. If it is a session cookie, the field will be unspecified, and the cookie disappears once you end your browsing session. If you set the expiry of the HttpOnly cookie to say a year, then the cookie persists across browsing sessions.

React frontend and REST API, CSRF

Using React on the frontend with a RESTful API as backend and authorisation by a JSON Web Token (JWT), how do we handle sessions? For example after login, I get a JWT token from REST. If I save it to localStorage I am vulnerable to XSS, if I save it to cookies, same problems except I set cookies to HttpOnly, but React can't read HttpOnly Cookies (I need to read cookie to take JWT from it, and use this JWT with REST requests), also I didn't mention the Cross Site Request Forgery (CSRF) problem. If you're using REST as backend, you can't use CSRF Tokens.
As a result, React with REST seems like a bad solution and I need to rethink my architecture. Is it possible to offer your users a secure React application that handles all business logic on the REST API side without fear of losing their data?
Update:
As far as I understood, it is possible to do this:
React makes an AJAX call to the REST API
React gets a JWT token from the REST API
React writes HttpOnly cookie
Because React can't read HttpOnly cookies, we use it as-is in all our REST calls where we need authentication
The REST API calls to check the XMLHttpRequest header, which is some kind of CSRF protection
The REST API side checks for cookie, reads JWT from it and does stuff
I lack theoretical knowledge here. The logic looks pretty secure, but I still need an answer to my questions and approve of this "workflow".
React makes AJAX call to REST API
assured, lots of restful resource client lib available
React gets JWT token from REST
assured, this is what JWT should do
React writes httponly cookie
I don't think so, It should not work, but session is not such a important thing, it'll soon get out of date, and recheck password on key operations, even the hackers got it in a very short time, you can bind session token together with IP when user login and check it in your backend apis. If you want it most secured, just keep token in memory, and redo login when open new page or page refreshes
Because react can't read httponly cookie, we use it as-is in our all REST call where we need authentication
assured, check user and permissions through login token, like csrf you can put your login token into your request header, and check it in your backend apis.
Bind login token to your own restful lib will save you a lot codes
REST on calls checks XMLHttpRequest header, what is some kind of CSRF protection
REST side check for cookie, read JWT from it and do stuff
assured, as most people do.
Also, bind csrf token to your own restful lib will save you a lot codes
use user token in header https://www.npmjs.com/package/express-jwt-token
Authorization JWT < jwt token >
use csrf token in header https://github.com/expressjs/csurf
req.headers['csrf-token'] - the CSRF-Token HTTP request header.
restful client https://github.com/cujojs/rest
react with jwt https://github.com/joshgeller/react-redux-jwt-auth-example
Your server can set the JWT cookie directly as a response to the login request.
The server responds to POST /login with Set-Cookie: JWT=xxxxxx. That cookie is http only and therefore not vulnerable to XSS, and will be automatically included on all fetch requests from the client (as long as you use withCredentials: true).
CSRF is mitigated as you mentioned, see OWASP for details.

Angular (or something else) isn't saving JSESSIONID cookie

I'm setting up a simple authentication service for my angular website using Spring for my backend and I have a following problem.
When I send a cross domain get request with credentials (REST controller on backend), I get authorized by Spring Security, I get a JSESSION cookie and all is fine. What's not fine is that the cookie isn't saved and I can't access it in any way I could think of to save it manually.
Am I missing something here? If you need additional information, I'd be glad to provide it.
#Edit
I have Set-Cookie header in my response:
(...)
Server
WildFly/8
Set-Cookie
JSESSIONID=CODE; path=/PATH
(...)

Session Token Authentication Security

I need some advice regarding using session tokens to authenticate users. I am building an AngularJS app which uses an API to tie in with the backend. I am only building the front end, not the backend. The documentation states that all calls to the API have a session token attached in the body of the request (POST).
I would like to know about the security of storing this token in localStorage. That is where I am storing it now and retrieving and attaching it to each API request. After login, the server sends the session token in the body and I save it from there.
There is no documentation about an x-access-token header that should be sent with the request made to the server. It is not being checked server side. What are the implications of this? I feel that it is susceptible to attacks without this added layer of security.
My main concern is the security of this setup. I want to know what the best setup is to make sure this app is as secure as possible and recommend changes to the way the backend is setup to facilitate this.
Thanks!
As you tell, you are only working on the UI part and not the backend. It is up to the backend team to ensure headers are properly evaluated and security is enforced (btw request headers do not belong to request body). Just put the token into the x-access-token header as they tell.
Storing the token inside the localStorage gives you a little more control over the cookie: You will not accidentally send it to unnecessary URLs. However, older browsers do not support it - you may need to use a shim for that.
In a case of SPA, you may consider not storing the token at all: It could be fetched each time your application is accessed and then stored within a service in angularjs, but it depends how your fetch/login operation is implemented (is it always interactive, how long does it take, etc).
I would suggest use $cookies rather than localstorage. As localstorage does not support some legacy browser.
I am using cookies to store token in my project

Resources