{"id":22009730,"url":"https://github.com/zitadel/example-quote-generator-app","last_synced_at":"2025-10-11T03:30:20.208Z","repository":{"id":176639185,"uuid":"657020346","full_name":"zitadel/example-quote-generator-app","owner":"zitadel","description":"A simple web application using a React front-end and a Python back-end API, both secured using ZITADEL.","archived":false,"fork":false,"pushed_at":"2023-06-27T11:00:24.000Z","size":10706,"stargazers_count":12,"open_issues_count":2,"forks_count":3,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-06-01T18:47:35.323Z","etag":null,"topics":["api-rest","auth","examples","examples-","examples-re"],"latest_commit_sha":null,"homepage":"https://zitadel.com/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/zitadel.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-06-22T06:29:28.000Z","updated_at":"2025-03-12T16:06:31.000Z","dependencies_parsed_at":null,"dependency_job_id":"9c844a0a-fa86-4ef8-833d-706e92f0729e","html_url":"https://github.com/zitadel/example-quote-generator-app","commit_stats":null,"previous_names":["zitadel/example-quote-generator-app"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/zitadel/example-quote-generator-app","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zitadel%2Fexample-quote-generator-app","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zitadel%2Fexample-quote-generator-app/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zitadel%2Fexample-quote-generator-app/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zitadel%2Fexample-quote-generator-app/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zitadel","download_url":"https://codeload.github.com/zitadel/example-quote-generator-app/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zitadel%2Fexample-quote-generator-app/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279006109,"owners_count":26084026,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-11T02:00:06.511Z","response_time":55,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api-rest","auth","examples","examples-","examples-re"],"created_at":"2024-11-30T02:10:35.979Z","updated_at":"2025-10-11T03:30:19.621Z","avatar_url":"https://github.com/zitadel.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# example-quote-generator-app\nA simple web application using a React front-end and a Python back-end API, both secured using ZITADEL.\n\n\u003cimg\n    src=\"screenshots/1.png\"\n    width=\"75%\"\n    alt=\"Landing Page\"\n/\u003e\n\n\u003cimg\n    src=\"screenshots/2.png\"\n    width=\"75%\"\n    alt=\"Login Page\"\n/\u003e\n\n\u003cimg\n    src=\"screenshots/3.png\"\n    width=\"75%\"\n    alt=\"Login Page\"\n/\u003e\n\n\u003cimg\n    src=\"screenshots/4.png\"\n    width=\"75%\"\n    alt=\"Post-Login Landing Page\"\n/\u003e\n\n\u003cimg\n    src=\"screenshots/5.png\"\n    width=\"75%\"\n    alt=\"Post API Call\"\n/\u003e\n\n## Prerequisites to run the app: \n\n- Have python3 and pip3 installed in your machine (for the backend)\n- Have Node.js installed in your machine (for the frontend)\n- Create a free ZITADEL account here - https://zitadel.cloud/\n- Create an instance as explained [here](https://zitadel.com/docs/guides/start/quickstart#2-create-your-first-instance). \n- Create a new project in your instance by following the steps [here](https://zitadel.com/docs/guides/start/quickstart#2-create-your-first-instance).\n\n## Run the backend\n\n### Register the API in ZITADEL\n\nFollow these [instructions](https://github.com/zitadel/examples-api-access-and-token-introspection/tree/main/api-basic-authentication#1) to register an API application with Basic Authentication in ZITADEL.\n\n### Run the API \n\nThe API has a single route:\n\n- \"/api/custom_quote\" - A valid access token is required.\n\n1. Create a folder named backend and add all the files in [/backend](https://github.com/zitadel/example-quote-generator-app/tree/main/backend) into it. \n2. cd to the backend directory: `cd backend`\n3. Create a new virtual environment for this project by running `python3 -m venv env`.\n4. Install required dependencies by running `pip3 install -r requirements.txt` on your terminal.\n5. Replace the values of `ZITADEL_DOMAIN`, `ZITADEL_INTROSPECTION_URL`, `API_CLIENT_ID` and `API_CLIENT_SECRET` in the .env file with your values you obtained earlier. \n6. Run the API by running `python3 server.py` in the terminal.\n\n\n### Obtain an access token via service user\n\n1. Create a service user as instructed [here]([https://github.com/zitadel/examples-api-access-and-token-introspection/tree/main/service-user-client-credentials](https://github.com/zitadel/examples-api-access-and-token-introspection/tree/main/service-user-client-credentials#2-create-a-service-user-with-client-credentials-in-zitadel-)https://github.com/zitadel/examples-api-access-and-token-introspection/tree/main/service-user-client-credentials#2-create-a-service-user-with-client-credentials-in-zitadel-). You can skip creating the role and authorization.\n2. Obtain a token by running the client-credentials-token-generator.py as instructed [here](https://github.com/zitadel/examples-api-access-and-token-introspection/tree/main/service-user-client-credentials#3-generate-a-token-). You can perform the instructions in this directory in a different terminal.\n\n### Test the API with the access token\n\n1. Invoke the API using the following cURL command:\n`curl -X GET -H \"Authorization: Bearer $TOKEN\" http://localhost:5000/api/custom_quote`\n\n2. You should get a response with Status Code 200 in the following format: \n`{\"quote\":\"If you're going through hell, keep going. - Winston Churchill\"}`\n\nNow the API is ready to be consumed by our front-end application. \n\n## Run the frontend application\n\n1. Follow the ZITADEL [Quickstart Guide](https://zitadel.com/docs/guides/start/quickstart) up to [Create your React application with ZITADEL OIDC PKCE authentication](https://zitadel.com/docs/guides/start/quickstart#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:\n- 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.\n\n\u003cimg\n    src=\"screenshots/8.png\"\n    width=\"75%\"\n    alt=\"Project\"\n/\u003e\n\n- Also, you do not need to create roles and authorizations as stated in the Quickstart.\n- Make sure to modify the Zitadel redirect_uri configuration to be just `http://localhost:3000/` (the Quickstart guide uses `http://localhost:3000/callback`).\n\n\u003cimg\n    src=\"screenshots/6.png\"\n    width=\"75%\"\n    alt=\"Redirect Settings\"\n/\u003e\n\n- You must also go to Token Settings in the front-end app and select User Info inside ID Token as shown below:\n\n\u003cimg\n    src=\"screenshots/7.png\"\n    width=\"75%\"\n    alt=\"Token Settings\"\n/\u003e\n\n3. Navigate to the folder where you want to create the React app. \n4. Run the following command to create a new React app named \"zitadel-app\": `npx create-react-app zitadel-app`\n5. Navigate to the \"zitadel-app\" folder: `cd zitadel-app`\n6. Install the dependencies by running the following: `npm install --save jwt-decode oidc-client-ts react react-dom react-router-dom`\\\n7. Replace the content in your `App.js` file with [src/App.js](https://github.com/zitadel/example-quote-generator-app/blob/main/frontend/src/App.js).\n8. Create a file named `Login.js` and paste the code in [src/Login/js](https://github.com/zitadel/example-quote-generator-app/blob/main/frontend/src/Login.js).\n9. Create a file named `authConfig.js` and add to it the content from [src/authConfig.js](https://github.com/zitadel/example-quote-generator-app/blob/main/frontend/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.\n10. 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](https://github.com/zitadel/example-quote-generator-app/blob/main/frontend/src/style.css).\n11. Create a folder called `images` and add the image in the [/images](https://github.com/zitadel/example-quote-generator-app/tree/main/frontend/src/images) folder.\n12. Add the line `\"proxy\": \"http://localhost:5000\"` (the URL of the back-end API) to your `package.json` file so that it looks something like this:\n```\n    {\n      \"name\": \"my-app\",\n      \"version\": \"0.1.0\",\n      \"private\": true,\n      \"proxy\": \"http://localhost:5000\",\n      \"dependencies\": {\n        \"react\": \"^17.0.1\",\n        \"react-dom\": \"^17.0.1\",\n        \"react-scripts\": \"4.0.1\",\n        //...\n      },\n      //...\n    }\n```\n    \n\nThe \"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.\nSo, in the React code, the fetch request looks like:\n\n```\nfetch('/api/custom_quote')\n  .then(response =\u003e response.json())\n  .then(data =\u003e this.setState({ quote: data.quote }));\n```\n\nPlease note that this only works when you're running your React app using the development server with `npm start` or `yarn start`. \n\n13. Run `npm start` inside the zitadel-app folder. If everything is set up properly, you will have your application running at `http://localhost:3000/`.\n\n## Test the web application end-to-end\n\n1. 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. \n2. The user will be redirected to ZITADEL where he has to log in as a ZITADEL user.\n3. If the login was successful, ZITADEL will send an access token along with an id token to the front-end application.\n4. 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.\n5. When the user presses the 'Generate quote\" button, the back-end API will be called with the user's access token.\n6. 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.\n7. The user will be abe to view the quote on the browser. \n \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzitadel%2Fexample-quote-generator-app","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzitadel%2Fexample-quote-generator-app","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzitadel%2Fexample-quote-generator-app/lists"}