{"id":18048073,"url":"https://github.com/ivangfr/okta-springboot-react","last_synced_at":"2025-04-10T09:49:09.089Z","repository":{"id":38315058,"uuid":"189773420","full_name":"ivangfr/okta-springboot-react","owner":"ivangfr","description":"The goal of this project is to implement an application where a user can manage (create/read/update/delete) jobs. For it, we will create: a backend Restful API called jobs-api and a frontend user interface called jobs-ui. Furthermore, we will use Okta to secure the complete application.","archived":false,"fork":false,"pushed_at":"2024-10-09T20:04:29.000Z","size":104162,"stargazers_count":12,"open_issues_count":1,"forks_count":10,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-24T08:46:04.413Z","etag":null,"topics":["docker","elasticsearch","java","javascript","materializecss","okta","okta-spring-boot","react","spring-boot","spring-data-elasticsearch","spring-web-mvc","springdoc-openapi"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","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/ivangfr.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","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},"funding":{"github":"ivangfr"}},"created_at":"2019-06-01T20:08:48.000Z","updated_at":"2024-11-06T13:26:59.000Z","dependencies_parsed_at":"2024-03-15T18:24:58.420Z","dependency_job_id":"f2035322-0ad5-4c07-a591-9301138b1d83","html_url":"https://github.com/ivangfr/okta-springboot-react","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ivangfr%2Fokta-springboot-react","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ivangfr%2Fokta-springboot-react/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ivangfr%2Fokta-springboot-react/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ivangfr%2Fokta-springboot-react/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ivangfr","download_url":"https://codeload.github.com/ivangfr/okta-springboot-react/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248197459,"owners_count":21063619,"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","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":["docker","elasticsearch","java","javascript","materializecss","okta","okta-spring-boot","react","spring-boot","spring-data-elasticsearch","spring-web-mvc","springdoc-openapi"],"created_at":"2024-10-30T20:11:18.073Z","updated_at":"2025-04-10T09:49:09.068Z","avatar_url":"https://github.com/ivangfr.png","language":"JavaScript","funding_links":["https://github.com/sponsors/ivangfr"],"categories":[],"sub_categories":[],"readme":"# okta-springboot-react\n\nThe goal of this project is to implement an application where a user can manage (create/read/update/delete) jobs. For it, we will create a backend Restful API called `jobs-api` and a frontend application called `jobs-ui`. Furthermore, we will use [`Okta`](https://www.okta.com/) to secure the complete application.\n\n## Proof-of-Concepts \u0026 Articles\n\nOn [ivangfr.github.io](https://ivangfr.github.io), I have compiled my Proof-of-Concepts (PoCs) and articles. You can easily search for the technology you are interested in by using the filter. Who knows, perhaps I have already implemented a PoC or written an article about what you are looking for.\n\n## Additional Readings\n\n- \\[**Medium**\\] [**Implementing and Securing a Simple Spring Boot REST API with Okta**](https://medium.com/javarevisited/implementing-and-securing-a-simple-spring-boot-rest-api-with-okta-a5143696cd60)\n- \\[**Medium**\\] [**Implementing and Securing a Simple Spring Boot UI (Thymeleaf + RBAC) with Okta**](https://medium.com/javarevisited/implementing-and-securing-a-simple-spring-boot-ui-thymeleaf-rbac-with-okta-9489cbbcec25)\n- \\[**Medium**\\] [**Implementing and Securing a Spring Boot GraphQL API with Okta**](https://medium.com/javarevisited/implementing-and-securing-a-spring-boot-graphql-api-with-okta-78bc997359b4)\n- \\[**Medium**\\] [**Building a Single Spring Boot App with Keycloak or Okta as IdP: Introduction**](https://medium.com/@ivangfr/building-a-single-spring-boot-app-with-keycloak-or-okta-as-idp-introduction-2814a4829aed)\n\n## Project User Interface Preview\n\n![jobs-portal-preview](documentation/jobs-portal-preview.gif)\n\n## Project diagram\n\n![project-diagram](documentation/project-diagram.jpeg)\n\n## Applications\n\n- ### jobs-api\n\n  [`Spring Boot`](https://docs.spring.io/spring-boot/index.html) Web Java application that exposes a REST API for managing jobs. The job data are stored in [Elasticsearch](https://www.elastic.co/elasticsearch) It has some endpoints that are secured. `Okta` is used to handle authentication and authorization.\n  \n  The table below shows the endpoins, whether they are secured or not, and the authorization role required to access the secured ones.\n \n  | Endpoint                | Secured | Role                        |\n  | ----------------------- | ------- |-----------------------------|\n  | `GET /actuator/*`       |      No |                             |\n  | `POST /callback/token`  |      No |                             |\n  | `GET /api/jobs/newest`  |      No |                             |\n  | `POST /api/jobs`        |     Yes | `JOBS_STAFF`                |\n  | `PUT /api/jobs/{id}`    |     Yes | `JOBS_STAFF`                |\n  | `DELETE /api/jobs/{id}` |     Yes | `JOBS_STAFF`                |\n  | `GET /api/jobs/{id}`    |     Yes | `JOBS_STAFF, JOBS_CUSTOMER` |\n  | `PUT /api/jobs/search`  |     Yes | `JOBS_STAFF, JOBS_CUSTOMER` |\n\n- ### jobs-ui\n\n  [`React`](https://react.dev/) frontend application where customers can look for a job and staff members can handle jobs. In order to access it, a person must login. The authentication is handled by `Okta`.\n\n## Prerequisites\n\n- [`Java 21+`](https://www.oracle.com/java/technologies/downloads/#java21)\n- [`npm`](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm)\n- [`Docker`](https://www.docker.com/)\n- [`Okta` account](https://developer.okta.com/signup/)\n\n## Configuring Okta\n\n### Access Developer Edition Account\n\n- If you do not have a Developer Edition Account, you can create one at https://developer.okta.com/signup/\n- If you already have, access https://developer.okta.com/login/\n\n### Access Okta Admin Dashboard\n\nThe picture below shows how `Okta Admin Dashboard` looks like\n\n![okta-admin-dashboard](documentation/okta-admin-dashboard.jpeg)\n\n### Add Application\n\n- In the `Okta Admin Dashboard` main menu on the left, click `Applications` menu and then `Applications` sub-menu\n- On the next page, click `Create App Integration` button\n- Select `OIDC - OpenID Connect` as _Sign on method_ and `Single-Page Application` as _Application type_. Click `Next` button\n- Enter the following values in the form.\n  - General Settings\n    - App integration name: `Jobs Portal SPA`\n    - Grant type: check `Authorization Code` and `Implicit (hybrid)`\n    - Sign-in redirect URIs: `http://localhost:3000/implicit/callback` and `http://localhost:8080/callback/token`\n    - Sign-out redirect URIs: `http://localhost:3000`\n  - Assignments\n    - Controlled access: `Skip group assignment for now`\n- Click `Save` button\n- On the next screen, the `Client ID` of `Jobs Portal SPA` is displayed. The `Okta Domain` can be obtained by clicking the button-menu present on the up-right corner of the screen.\n\n### Create groups\n\n- In the `Okta Admin Dashboard` main menu on the left, click `Directory` menu and then `Groups` sub-menu\n- Add Staff Group\n  - Click `Add Group` button\n  - Enter `JOBS_STAFF` for the _Name_ text-field\n  - Click `Save` button\n- Add Customer Group\n  - Click `Add Group` button\n  - Enter `JOBS_CUSTOMER` for the _Name_ text-field\n  - Click `Save` button\n\n### Add people\n\n- In the `Okta Admin Dashboard` main menu on the left, click `Directory` menu and then `People` sub-menu\n- Click `Add person` button\n- Enter the following information for the Staff person\n  - First name: `Mario`\n  - Last name: `Bros`\n  - Username: `mario.bros@test.com`\n  - Primary email: `mario.bros@test.com`\n  - Groups: `JOBS_STAFF` (the group will popup; select it to add it)\n  - Password: `Set by admin`\n  - Set a strong password in the text-field that will appear\n  - `Uncheck` the check-box that says _\"User must change password on first login\"_\n  - Click `Save and Add Another` button\n- Enter the following information for the Customer person\n  - First name: `Luigi`\n  - Last name: `Bros`\n  - Username: `luigi.bros@test.com`\n  - Primary email: `luigi.bros@test.com`\n  - Groups: `JOBS_CUSTOMER` (the group will popup; select it to add it)\n  - Password: `Set by admin`\n  - Set a strong password in the text-field that will appear\n  - Leave `Uncheck` the check-box that says _\"User must change password on first login\"_\n  - Click `Save` button\n\n### Assign Groups to Application\n\n- In the `Okta Admin Dashboard` main menu on the left, click `Directory` menu and then `Groups` sub-menu\n- Select `JOBS_STAFF`\n- Click `Applications` tab\n- Click `Assign Applications` button\n- Click the `Assign` button related to `Jobs Portal SPA` and then click `Done`\n- In the `Okta Admin Dashboard` main menu on the left, click `Groups` sub-menu again\n- Select `JOBS_CUSTOMER`\n- Click `Applications` tab\n- Click `Assign Applications` button\n- Click the `Assign` button related to `Jobs Portal SPA` and then click `Done`\n\n### Add Claim\n\n- In the `Okta Admin Dashboard` main menu on the left, click `Security` menu and then `API` sub-menu\n- In `Authorization Servers` tab, select the `default`\n- In `Claims` tab, click `Add Claim`\n- Enter the following information for the claim\n  - Name: `groups`\n  - Include in token type:\n    - Select `Access Token`\n    - Keep `Always` in the right field\n  - Value type: `Groups`\n  - Filter:\n    - Select `Matches regrex`\n    - Set `.*` in the right field\n  - Include in: `Any scope`\n  - Click `Create` button\n\n## Start Environment\n\n- Open a terminal and inside `okta-springboot-react` root folder run\n  ```\n  docker compose up -d\n  ```\n\n- Wait for `elasticsearch` Docker container to be up and running. To check it, run\n  ```\n  docker compose ps\n  ```\n\n## Running applications\n\n- **jobs-api**\n\n  - In a terminal, navigate to `okta-springboot-react/jobs-api` folder\n\n  - Export the following environment variables. Those values were obtained while [adding Application](#add-application)\n    ```\n    export OKTA_DOMAIN=...\n    export OKTA_CLIENT_ID=...\n    ```\n\n  - Run the [`Maven`](https://maven.apache.org/) command below to start `jobs-api`\n    ```\n    ./mvnw clean spring-boot:run\n    ```\n\n- **jobs-ui**\n\n  - Open a new terminal and navigate to `okta-springboot-react/jobs-ui` folder\n\n  - Create a file called `.env.local` with the following content. Those values were obtained while [adding Application](#add-application)\n    ```\n    REACT_APP_OKTA_ORG_URL=https://\u003cOKTA_DOMAIN\u003e\n    REACT_APP_OKTA_CLIENT_ID=\u003cOKTA_CLIENT_ID\u003e\n    ```\n\n  - If you are running `jobs-ui` for the first time, execute the [`npm`](https://www.npmjs.com/) command below\n    ```\n    npm install\n    ```\n\n  - To start `jobs-api` run\n    ```\n    npm start\n    ```\n    It will open `job-ui` in a browser automatically.\n\n## Applications URLs\n\n| Application | URL                                   |\n| ----------- | ------------------------------------- |\n| jobs-api    | http://localhost:8080/swagger-ui.html |\n| jobs-ui     | http://localhost:3000                 |\n\n## Using jobs-ui\n\n- Open a browser and access http://localhost:3000\n\n- Click `Login` in the navigation bar\n\n- The Okta login page will appear. Enter the username \u0026 password of the person added at the step [`Configuring Okta \u003e Add people`](#add-people) and click `Sign In`.\n\n- Done!\n\n\u003e **Note**: If you are using the person `luigi.bros@test.com`, you will not be able to create/update/delete a job because it doesn't have the required role for it.\n\n## Getting Access Token\n\nIn order to use just the `jobs-api` endpoints, you must have an `JWT` access token. Below are the steps to get it.\n\n- In a terminal, create the following environment variables. Those values were obtained while [adding Application](#add-application)\n  ```\n  OKTA_DOMAIN=...\n  OKTA_CLIENT_ID=...\n  ```\n\n- Get Okta Access Token Url\n  ```\n  OKTA_ACCESS_TOKEN_URL=\"https://${OKTA_DOMAIN}/oauth2/default/v1/authorize?\\\n  client_id=${OKTA_CLIENT_ID}\\\n  \u0026redirect_uri=http://localhost:8080/callback/token\\\n  \u0026scope=openid\\\n  \u0026response_type=token\\\n  \u0026response_mode=form_post\\\n  \u0026state=state\\\n  \u0026nonce=myNonceValue\"\n\n  echo $OKTA_ACCESS_TOKEN_URL\n  ```\n\n- Copy the Okta Access Token Url from the previous step and paste it in a browser\n\n- The Okta login page will appear. Enter the username \u0026 password of the person added at the step [`Configuring Okta \u003e Add people`](#add-people) and click `Sign In` button\n\n- It will redirect to `/callback/token` endpoint of `jobs-api` and the `Access token` will be displayed, together with other information\n  ```\n  {\n    \"state\": \"state\",\n    \"access_token\": \"eyJraWQiOiJyNFdY...\",\n    \"token_type\": \"Bearer\",\n    \"expires_in\": \"3600\",\n    \"scope\": \"openid\"\n  }\n  ```\n  \u003e **Note**: In [jwt.io](https://jwt.io), you can decode and verify the `JWT` access token\n\n## Calling jobs-api endpoints using curl\n\n- **`GET /api/jobs/newest`**\n\n  The `api/jobs/newest` endpoint is public, so we can access it without any problem.\n  ```\n  curl -i http://localhost:8080/api/jobs/newest?number=2\n  ```\n  It should return\n  ```\n  HTTP/1.1 200\n  [{\"id\":\"uuulE2sBTYouQKNL1uoV\", ...},{\"id\":\"u-ulE2sBTYouQKNL1-qb\", ...}]\n  ```\n\n- **`GET /api/jobs` without Access Token**\n\n  Try to get the list of jobs without informing the access token.\n  ```\n  curl -i http://localhost:8080/api/jobs\n  ```\n  It should return\n  ```\n  HTTP/1.1 401\n  ```\n\n- **`GET /api/jobs` with Access Token**\n\n  First, get the access token as explained in [`Getting Access Token`](#getting-access-token) section. Then, create an environment variable for the access token.\n  ```\n  ACCESS_TOKEN=...\n  ```\n  \n  Call the get the list of jobs informing the access token\n  ```\n  curl -i http://localhost:8080/api/jobs -H \"Authorization: Bearer $ACCESS_TOKEN\"\n  ```\n  Response\n  ```\n  HTTP/1.1 200\n  {\"content\":[{\"id\":\"uISqEWsBpDcNLtN2kZv3\",\"title\":\"Expert Java Developer - Cloud\",\"company\":\"Microsoft\",\"logoUrl\"...}\n  ```\n\n  \u003e **Note**: If you are using the person `luigi.bros@test.com`, you will not be able to create/update/delete a job because it doesn't have the required role for it.\n\n## Using jobs-api with Swagger\n\n- First, get the access token as explained in [`Getting Access Token`](#getting-access-token) section.\n\n- Open `jobs-api` Swagger website http://localhost:8080/swagger-ui.html\n\n- Click `Authorize` button. Paste the access token in the `Value` field. Then, click `Authorize` and `Close` to finalize.\n\n- Done! You can now access the sensitive endpoints.\n\n\u003e **Note**: If you are using the person `luigi.bros@test.com`, you will not be able to create/update/delete a job because it doesn't have the required role for it.\n\n## Shutdown\n\n- Go to the terminals where `jobs-api` and `jobs-ui` are running and press `Ctrl+C`\n\n- To stop and remove containers, network and volumes, run in a terminal the following command inside `okta-springboot-react` root folder\n  ```\n  docker compose down -v\n  ```\n\n## Cleanup\n\n### Okta Configuration\n\n#### Delete Person\n\n- In the `Okta Admin Dashboard` main menu on the left, click `Directory` menu and then `People` sub-menu\n- Click `Mario Bros` in the People list\n- In `Mario Bros` profile, click `More Actions` multi-button and then `Deactivate`\n- Confirm deactivation by clicking `Deactivate` button\n- Still in `Mario Bros` profile, click `Delete` button\n- Confirm deletion by clicking `Delete` button\n- Click `Luigi Bros` in the People list\n- In `Luigi Bros` profile, click `More Actions` multi-button and then `Deactivate`\n- Confirm deactivation by clicking `Deactivate` button\n- Still in `Luigi Bros` profile, click `Delete` button\n- Confirm deletion by clicking `Delete` button\n\n#### Delete Groups\n\n- In the `Okta Admin Dashboard` main menu on the left, click `Directory` menu and then `Groups` sub-menu\n- Select `JOBS_CUSTOMER`\n- In `JOBS_CUSTOMER` profile, click `Actions` button and then `Delete` sub-button\n- Confirm deletion by clicking `Delete Group` button\n- Select `JOBS_STAFF`\n- In `JOBS_STAFF` profile, click `Actions` button and then `Delete` sub-button\n- Confirm deletion by clicking `Delete Group` button\n\n#### Delete Application\n\n- In the `Okta Admin Dashboard` main menu on the left, click `Applications` menu and then `Applications` sub-menu\n- In Application list whose status is `ACTIVE`, click `Jobs Portal SPA`'s `gear` icon and then click `Deactivate`\n- Confirm deactivation by clicking `Deactivate Application` button\n- In Application list whose status is `INACTIVE`, click `Jobs Portal SPA`'s `gear` icon and then click `Delete`\n- Confirm deletion by clicking `Delete Application` button\n\n#### Delete Claim\n\n- In the `Okta Admin Dashboard` main menu on the left, click `Security` menu and then `API` sub-menu\n- In `Authorization Servers` tab, select the `default`\n- In `Claims` tab, click the `x` icon related to the `groups` claim created\n- Confirm deletion by clicking `OK` button\n\n## How to upgrade jobs-ui dependencies to latest version\n\n- In a terminal, make sure you are in `okta-springboot-react/jobs-ui` folder\n\n- Run the following commands\n  ```\n  npm upgrade\n  npm i -g npm-check-updates\n  ncu -u\n  npm install\n  ```\n\n## References\n\n- https://www.npmjs.com/package/@okta/okta-react\n- https://developer.okta.com/code/react/okta_react_sign-in_widget/\n- https://developer.okta.com/blog/2019/03/06/simple-user-authentication-in-react\n- https://dzone.com/articles/23-useful-elasticsearch-example-queries\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fivangfr%2Fokta-springboot-react","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fivangfr%2Fokta-springboot-react","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fivangfr%2Fokta-springboot-react/lists"}