A simple web application using a React front-end and a Python back-end API, both secured using ZITADEL.
- Have python3 and pip3 installed in your machine (for the backend)
- Have Node.js installed in your machine (for the frontend)
- Create a free ZITADEL account here - https://zitadel.cloud/
- Create an instance as explained here.
- Create a new project in your instance by following the steps here.
Follow these instructions to register an API application with Basic Authentication in ZITADEL.
The API has a single route:
- "/api/custom_quote" - A valid access token is required.
- Create a folder named backend and add all the files in /backend into it.
- cd to the backend directory:
cd backend
- Create a new virtual environment for this project by running
python3 -m venv env
. - Install required dependencies by running
pip3 install -r requirements.txt
on your terminal. - Replace the values of
ZITADEL_DOMAIN
,ZITADEL_INTROSPECTION_URL
,API_CLIENT_ID
andAPI_CLIENT_SECRET
in the .env file with your values you obtained earlier. - Run the API by running
python3 server.py
in the terminal.
- Create a service user as instructed here. You can skip creating the role and authorization.
- Obtain a token by running the client-credentials-token-generator.py as instructed here. You can perform the instructions in this directory in a different terminal.
-
Invoke the API using the following cURL command:
curl -X GET -H "Authorization: Bearer $TOKEN" http://localhost:5000/api/custom_quote
-
You should get a response with Status Code 200 in the following format:
{"quote":"If you're going through hell, keep going. - Winston Churchill"}
Now the API is ready to be consumed by our front-end application.
- Follow the ZITADEL Quickstart Guide up to Create your React application with ZITADEL OIDC PKCE authentication. We will go through the steps to create the React app for this tutorial below. But before that, here are some changes to note:
- Since you already created an instance and project for the backend, you can use the same project to create the Single Page Application in ZITADEL (or you can follow the guide and create a new project altogether as well). The front-end application and API application were both created in the same ZITADEL project for this app as shown below.
- Also, you do not need to create roles and authorizations as stated in the Quickstart.
- Make sure to modify the Zitadel redirect_uri configuration to be just
http://localhost:3000/
(the Quickstart guide useshttp://localhost:3000/callback
).
- You must also go to Token Settings in the front-end app and select User Info inside ID Token as shown below:
- Navigate to the folder where you want to create the React app.
- Run the following command to create a new React app named "zitadel-app":
npx create-react-app zitadel-app
- Navigate to the "zitadel-app" folder:
cd zitadel-app
- Install the dependencies by running the following:
npm install --save jwt-decode oidc-client-ts react react-dom react-router-dom
\ - Replace the content in your
App.js
file with src/App.js. - Create a file named
Login.js
and paste the code in src/Login/js. - Create a file named
authConfig.js
and add to it the content from src/authConfig.js. Edit the file by adding your values your obtained from ZITADEL. Make sure the PROJECT_ID in the scope is replaced with the project ID of the project where your API resides. - Add a new file called
style.css
to the src folder to apply CSS styling to the pages. Copy paste the code from src/style.css. - Create a folder called
images
and add the image in the /images folder. - Add the line
"proxy": "http://localhost:5000"
(the URL of the back-end API) to yourpackage.json
file so that it looks something like this:
{
"name": "my-app",
"version": "0.1.0",
"private": true,
"proxy": "http://localhost:5000",
"dependencies": {
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-scripts": "4.0.1",
//...
},
//...
}
The "proxy" field in package.json tells the development server to proxy any unknown requests to the specified address. This helps us bypass CORS issues because the requests will be served from the same domain as far as the client (browser) is concerned. So, in the React code, the fetch request looks like:
fetch('/api/custom_quote')
.then(response => response.json())
.then(data => this.setState({ quote: data.quote }));
Please note that this only works when you're running your React app using the development server with npm start
or yarn start
.
- Run
npm start
inside the zitadel-app folder. If everything is set up properly, you will have your application running athttp://localhost:3000/
.
- Test the application by clicking on the log in button. The front-end app uses Authorization Code with PKCE flow for user authentication using ZITADEL.
- The user will be redirected to ZITADEL where he has to log in as a ZITADEL user.
- If the login was successful, ZITADEL will send an access token along with an id token to the front-end application.
- The front-end application will greet the user and show the option to generate a quote via a button. The user's name was extracted from the id_token returned by ZITADEL.
- When the user presses the 'Generate quote" button, the back-end API will be called with the user's access token.
- The back-end API is protected and will introspect the access token by calling ZITADEL's introspection endpoint. If the access token is active/valid, the API will send the response to the front-end application.
- The user will be abe to view the quote on the browser.