Webpack dev server with proxy does not handle redirects - reactjs

I am developing a react application. For development I am using webpack dev server. My backend application is a spring boot. When I make a request and I am not authenticated the backend redirects me to the login page (localhost:8080/login).
My webpack dev server runs on port 3000. All my api call are redirected to the backend using a proxy from the devserver.
devServer: {
historyApiFallback: true,
contentBase: './',
proxy: [{
context: ["/api"],
target: "http://localhost:9090"
}],
changeOrigin: true,
secure: false
When I access a protected resource and I am not authenticated, for example localhost:3000/api/test, I am redirected to localhost:8080/login and I can see 2 request: a 302 request and a 200 request to /login. The problem is that the dev server does not actually do the redirect and does not show the login page. When serving the content from my spring boot application the redirect is done.
Is this a problem related to webpack dev server or is there something wrong in my understanding of the proxy mechanism?

Related

How to configure a react capacitor app running on mobile by usb to make http request to sendbird as localhost instead of its IP address?

I have a React webapp that I have converted it to native app using Capacitor. For live reloading, I had to edit capacitor.config.json as follows:
const config: CapacitorConfig = {
//
webDir: 'build',
bundledWebRuntime: false,
server: {
url: 'http://192.XXX.XXX:3000',
cleartext: true
},
};
This works just fine until the app makes a request to sendbird for initialization. I get the error message: 'SendBirdCall needs https connection, except for 'localhost' or '127.0.0.1'. I tried to setup an express https server but failed. Later I created two channels using ngrok - one for the server and one for the app. The sendbird request was successful but the graphql websocket was failing as ngrok does not support websocket links, also tried a tcp link but it failed as well.
I have another app that I created using the Sendbird React Native Quickstart project and I did not need to do any configuration for that. What could be done in order to make sendbird request using localhost from mobile connected via usb while also being able to have a ws connection?
Try to change the url:
const config: CapacitorConfig = {
...
server: {
url: 'http://localhost:3000',
cleartext: true
},
};
And after connecting a physical device execute the following:
cd $ANDROID_HOME/platform-tools
./adb reverse tcp:3000 tcp:3000
Where $ANDROID_HOME is the Android SDK directory.

webpack config : How do I add a request header when directing requests to proxy server?

I am working on a react app, where while development we need to direct some requests to a backend server. I have added devServer.proxy option for that in webpack.config.js file -
config.devServer.proxy = {
"/apiV2": {
target: "https://beserveraddress:8080",
changeOrigin: true,
secure: false,
}
}
However I need to add custom cookie header value when redirecting to this backend server.
I have tried headers option but not able to get result. How can I add 'Cookie' header to the request before it is directed to backend proxy server?

ReactJS proper configuration of OIDC on Kong + Keycloak

I am wondering what should be the proper configuration when I have the ReactJS front end application and I want to give access to BE only to authorized and authenticated users through OIDC.
I have the following setup:
Browser ----> Kong ----> /admin* (ReactJS FE)
----> /api* (BE REST API)
|
Keycloak
The goal here is that the Kong will do the authorization and authentication so it can be externalized from the application.
Kong is using OIDC plugin that can handle authorization when the user would like to open application in browser and is not authorized. It will redirect to Keycloak, and once user is authorized, it will come back to Kong for further processing of JWT token.
This will happen when user hits for example https://localhost:8000/admin. So far, so good.
Now, the actual functionality is provided by the /api* end points. Therefore I need to get the token or cookie and be able to validate the token to have access to the API (here we are authenticating user).
What is the proper way how to configure this? Should be the API also protected by OIDC with the same flow, or it should only validate JWT.
The first option, when the /api* has the OIDC plugin enabled:
open https://localhost:8000/admin with unauthorized user
Kong will detect it and use the OIDC plugin to authorize through Keycloak
browser is redirected to Keycloak, user will provide credentials
browser will send info about authorization back to Kong, and it will finish authorization and get the JWT token
from now on, the ReactJS FE will use cookies and eventually JWT token to access the https://localhost:8000/api* from the ReactJS application
Now, when the access is expired or revoked, and the ReactJS application is still opened, I get errors, because the OIDC plugin will try to redirect on /api* calls with 302, however I am still in the ReactJS app, and it cannot handle it. The only way here is to refresh the complete ReactJS app and it will do the authorization again and it will work.
Here, I am utilizing kong-oidc plugin.
The second option I am thinking about, when the /api* route does not use OIDC plugin, but only validates JWT tokens:
open https://localhost:8000/admin with unauthorized user
Kong will detect it and use the OIDC plugin to authorize through Keycloak
browser is redirected to Keycloak, user will provide credentials
browser will send info about authorization back to Kong, and it will finish authorization and get the JWT token
from now on, the ReactJS FE will use cookies and eventually JWT token to access the https://localhost:8000/api* from the ReactJS application
When the session is expired or revoked, the ReactJS application will start getting the 401 unauthorized instead of 302. In this case, the ReactJS should know that it should start the OIDC again to get new token, or refresh.
In this second options, I can use kong-oidc plugin for OIDC on the ReactJS, and kong-plugin-jwt-keycloak plugin for validation of tokens on the API level.
I currently have the following configuration of Kong, which should be behaving according the first option:
_format_version: '2.1'
_transform: true
services:
- name: core
host: core-service
port: 8080
protocol: http
routes:
- name: core_route-oidc
strip_path: false
paths:
- /api*
plugins:
- name: oidc
config:
client_secret: s0qKH5qItTWoxpBt7Zrj348ZhZ7woAbk
client_id: kong
bearer_only: 'no'
realm: Kong
introspection_endpoint: >-
https://keycloak.local/realms/Kong/protocol/openid-connect/token/introspect
discovery: >-
https://keycloak.local/realms/Kong/.well-known/openid-configuration
- name: request-transformer
config:
remove:
headers:
- cookie
- name: fe-administrator
host: fe-administrator-service
port: 80
protocol: http
path: /
routes:
- name: fe-administrator_route-oidc
strip_path: false
paths:
- /admin*
plugins:
- name: oidc
config:
client_secret: s0qKH5qItTWoxpBt7Zrj348ZhZ7woAbk
client_id: kong
bearer_only: 'no'
realm: Kong
introspection_endpoint: >-
https://keycloak.local/realms/Kong/protocol/openid-connect/token/introspect
discovery: >-
https://keycloak.local/realms/Kong/.well-known/openid-configuration
- name: request-transformer
config:
remove:
headers:
- cookie
plugins:
- name: cors
config:
origins:
- '*'
credentials: true
max_age: 3600
exposed_headers:
- X-Auth-Token
preflight_continue: false
But I am wondering if this is proper configuration. Also, if some client application would like to access only /api*, without accessing the ReactJS front end application, it will not use the same OIDC flow, do I understand it correctly?
Should be the /api* configured according second option and provides validation of JWT tokens only? Something like the following Kong config:
_format_version: '2.1'
_transform: true
services:
- name: core
host: core-service
port: 8080
protocol: http
routes:
- name: core_route-oidc
strip_path: false
paths:
- /api*
plugins:
- name: jwt-keycloak
config:
allowed_iss: >-
https://keycloak.local/realms/Kong
- name: request-transformer
config:
remove:
headers:
- cookie
- name: fe-administrator
host: fe-administrator-service
port: 80
protocol: http
path: /
routes:
- name: fe-administrator_route-oidc
strip_path: false
paths:
- /admin*
plugins:
- name: oidc
config:
client_secret: s0qKH5qItTWoxpBt7Zrj348ZhZ7woAbk
client_id: kong
bearer_only: 'no'
realm: Kong
introspection_endpoint: >-
https://keycloak.local/realms/Kong/protocol/openid-connect/token/introspect
discovery: >-
https://keycloak.local/realms/Kong/.well-known/openid-configuration
- name: request-transformer
config:
remove:
headers:
- cookie
plugins:
- name: cors
config:
origins:
- '*'
credentials: true
max_age: 3600
exposed_headers:
- X-Auth-Token
preflight_continue: false
And the ReactJS application must properly handle 401 unauthorized.
I would like to understand how this should be done properly.
Implementing an SPA secured by cookies is tricky. It is worth comparing against the behaviour of a backend for frontend, the second of the below roles, and basing your solution on that.
URLs
https://www.myapp.com/admin: downloads the index.html for the SPA, and other static resources
https://www.myapp.com/api: a cookie secured API entry point for a particular SPA
https://api.mycompany.com/api: a public API URL that can be called with access tokens
COOKIE API ROUTE
The second URL is called during Ajax requests from the SPA. There should be no OIDC or redirects here, just cookie / token validation and forwarding.
This route should translate cookies to tokens, apply CSRF checks, then forward the token to the API. If the cookie / token is invalid or expired a 401 should be returned. The keycloak plugin you mention expects to receive JWTs, not cookies.
BACKEND FOR FRONTEND
A BFF would run on the second URL and provide endpoints tailored to what the React app needs, such as these:
https://www.myapp.com/bff/login/start: Return a login redirect URL for the SPA
https://www.myapp.com/bff/login/end: Process a login response URL and write cookies
https://www.myapp.com/bff/refresh: Refresh access tokens represented by cookies
https://www.myapp.com/bff/logout/start: Return a logout redirect URL for the SPA
It can be difficult to implement a BFF as an API gateway plugin, so sometimes it is instead implemented as a utility API, which runs behind the gateway.

ReactJS/Next.js: CRA Proxy Does Not Work With Next.js (Attempting To Route API Request To Express server)

I'm currently upgrading a vanilla React app to use Next.js (version 7.0.0). The app was originally built with Create-React-App and utilizes the proxy built in to CRA's server.
In development my React app runs on port 3000 and I have an Express server running on port 5000. Prior to adding Next.js I'd been using a proxy object within the package.json file to route API requests to the server.
API request:
const res = await axios.get('/api/request')
Proxy object in package.json:
"proxy": {
"/api/*": {
"target": "http://localhost:5000"
}
}
This had been working great, but with Next.js I'm now getting an error:
GET http://localhost:3000/api/request 404 (Not Found)
^ This is supposed to be pointing to locahost:5000 (my server)
Does anyone know how I might be able to route API requests from a React/Next.js client to an Express server running on a different port?
OK, so I've figured this out. You can create a Node.js proxy for Express by using http-proxy-middleware
You can then configure the target option to proxy requests to the correct domain:
const proxy = require('http-proxy-middleware')
app.use('/api', proxy({ target: 'http://localhost:5000', changeOrigin: true }));

webpack-dev-server develop on https

My .NET Core API is exposed over https.
I want to do request to API from my React app running on webpack-dev-server. But webpack-dev-server running on http by default and CORS block any requests.
I reconfigure webpack to force use https (with my *.pfx certificate example),
but then i have 'private connection error' in browser at every refresh (minor problem) and auto-refreshing stops working.
console errors:
> [HMR] Waiting for update signal from WDS...
> app.js:4049 WebSocket connection to 'wss://localhost:8080/sockjs-node/826/sy0x5mcu/websocket' failed: Error in connection establishment: net::ERR_INSECURE_RESPONSE
> [WDS] Hot Module Replacement enabled.
I think that websockets of webpack-dev-server can not establish connection because of https url. But i do not know how to fix this.
Proxy your .NET core api in your webpack dev server config
{
proxy: {
'/api/**': {
target: 'https://localhost:443', // or whichever port it's listening on
secure: false,
changeOrigin: true, // this might not be necessary depending on how restrictive your host is
pathRewrite: {'^/api' : ''}, // rewrite request /api/foo -> https://localhost:443/foo
},
}
}
More docs on proxying with webpack dev server:
https://webpack.js.org/configuration/dev-server/#devserverproxy

Resources