Before we dive into the details, here is a video that walks through the demo and configurations.
Recently, we have completed the form authentication in the light-oauth2 authorization code service. Now, we support Basic Authentication, Form Authentication, and SPENGO SSO.
While working on the form authentication, I have to set up my local environment in a production-like configuration before deploying it to the cloud to provide services to our users.
The setup consists of:
light-oauth2 started with a docker-compose for all eight services along with a MySQL database.
light-router started with another docker-compose to handle the SPA security with light-spa-4j StateLessAuthHandler and serve two virtual hosts lightapi.net (portal) and signin.lightapi.net(sign in).
As we are trying to mimic the production environment on the local desktop, we want to make sure that it behaves the same. With at least two virtual hosts that are served by the light-router instance, we need to update the /etc/hosts to map the DNS. Add the following line to the /etc/hosts file.
192.168.1.144 lightapi.net signin.lightapi.net
You must change the IP address if you want to try it on your local. You can find your IP with ifconfig command.
When we start the router, we are using 8443 as the port number in docker-compose or start it standalone in the IDE for debugging. However, we don’t want to see the port number on the browser. So we need to map the default https port 443 to 8443 on my local. Please follow this tutorial to set up the iptables.
All the light-oauth2 services will be registered to the consul server running locally, to start it.
docker-compose -f docker-compose-consul.yml up -d
We need to start the light-oauth2 services with one of the supported databases. In this case, we are using MySQL as the backend database in a docker-compose.
You can find the configuration files along with a docker-compose file in light-config-test/light-oauth2/local-consul folder.
Here is the final docker-compose. Please note that network_mode is the host for all services.
Since all light-oauth2 services will be deployed behind the light-router, so there is no need to enable the CORS handlers for in-flight requests. We need to disable the CORS handler in the cors.yml file. Here is one of the examples.
As we don’t have the light-oauth2 console hooked up yet, we don’t have a chance to create a new client_id/client_secret pair. We need to rely on the create_mysql.sql script to populate a client for our test. There is an existing bootstrap client, and we just need to modify it with the following redirect_uri. The is the URI that will handle the authorization code returned from the light-oauth2 code service. The real handler is the light-spa-4j StatelessAuthHandler which is wired in the light-router handler.yml file.
To start the light-oauth2 services.
docker-compose up -d
The light-oauth2 consists of eight microservices which are listening to different ports when they are started with a docker-compose. To make sure that these services can be accessed as static IP and standard HTTPS port 443, we are going to deploy a light-router instance in front of light-oauth2 instances.
The light-oauth2 is part of the light-portal, so we don’t need to create a separate configuration folder. We can reuse the light-config-test/light-router/local-portal configuration folder for the exact purpose. Of course, the folder contains configuration files and virtual hosts for other portal services and sites.
We first need to add a brand new virtual host called signin for the form authentication of the light-oauth2 authorization code flow.
The source code of this single page application can be found at light-oauth2/login-view.
To map the new site in the docker-compose, we need to copy the build folder of the login-view to the same folder ~/networknt/light-config-test/light-router/local-portal/signin folder.
To build the React SPA, go to the light-oauth2/login-view folder, and run.
npm run build
We need to add a volume mapping in the docker-compose.yml for the light-router.
Note that we have added the following line to map the ./signin/build folder into the container /signin/build folder.
As the light-router instance is dealing with both lightapi.net and signin.lightapi.net domains, we need to update the cors.yml to allow these two domains to access each other.
We also need to update the client.yml to change the default redirect_uri for the authorization code flow to https://lightapi.net/authorization instead of default https://localhost:8080/authorization_code. This URI must match with the redirect_uri defined in the MySQL database which is required by the OAuth 2.0 specification. Also, the server_url is changed from localhost to lightapi.net as the router will be running inside a docker container.
# The scope token will be renewed automatically 1 minutes before expiry
# if scope token is expired, we need short delay so that we can retry faster.
# if scope token is not expired but in renew windown, we need slow retry delay.
# token server url. The default port number for token service is 6882.
# token service unique id for OAuth 2.0 provider
# the following section defines uri and parameters for authorization code grant type
# token endpoint for authorization code grant
# client_id for authorization code grant flow. client_secret is in secret.yml
# the web server uri that will receive the redirected authorization code
# optional scope, default scope in the client registration will be used if not defined.
In the handler.yml, we need to make the following update.
Add StatelessAuthHandler to the middleware handler definition.
Add a new path /authorization to accept the authorization code redirect. Basically, the request will be handled by the StatelessAuthHandler that is part of the default chain. The StatelessAuthHandler will receive the authorization code and go to the token service to get a JWT token then save the access token as well as csrf token in the secure cookies with HTTPS connection.
Since we have added StatelessAuthHandler to the handler chain, we need to add statelessAuth.yml to the config folder.
# Indicate if the StatelessAuthHandler is enabled or not
# Once Authorization is done, which path the UI is redirected.
# Request path for the authorization code handling.
# Cookie domain
# Cookie path
# Cookie maxAge
# Login uri, redirect to it once session is expired
# Cookie secured
While working on the configuration, I need to debug the light-router instance in the IDE. So I have created a new folder called debug along with config with only one file virtual-host.yml that is different.
In the debug folder, we are using the absolute path instead of the path within the docker container. Here is the example of signin site.
There are some hidden form fields that are getting from the query parameter from the redirect. When calling the fetch, note that we pass the redirect: ‘follow’ and the special code in the if block to redict to the response.url.
In the light-portal/view, we have updated the ResponsiveDrawer.js to add the following.
To test it, open a browser tab and enter the URL https://lightapi.net in the address bar. Once the single page application is loaded, click the AccountCircle button on the upper right. The browser will be redirected to the signin.lightapi.net to collect the user’s credential. Please use the following user to log in.
Once the login is successful, the control will be redirected back to the lightapi.net with a JWT token in the cookie.
To deploy the light-oauth2 in the production-like configuration on my local computer is the first step in implementing it to the cloud to provide services to our users.
Also, this tutorial can help our users to set up a local development environment for building applications and working on the frameworks.