{"id":17340865,"url":"https://github.com/kenfdev/hr-sample-app","last_synced_at":"2025-04-14T19:08:33.085Z","repository":{"id":41677068,"uuid":"421395811","full_name":"kenfdev/hr-sample-app","owner":"kenfdev","description":"Sample web application integrating with Oso","archived":false,"fork":false,"pushed_at":"2023-12-15T05:32:24.000Z","size":2300,"stargazers_count":8,"open_issues_count":7,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-14T19:08:26.893Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"TypeScript","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/kenfdev.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}},"created_at":"2021-10-26T11:25:51.000Z","updated_at":"2023-02-13T01:37:07.000Z","dependencies_parsed_at":"2023-02-17T03:31:26.266Z","dependency_job_id":null,"html_url":"https://github.com/kenfdev/hr-sample-app","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/kenfdev%2Fhr-sample-app","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kenfdev%2Fhr-sample-app/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kenfdev%2Fhr-sample-app/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kenfdev%2Fhr-sample-app/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kenfdev","download_url":"https://codeload.github.com/kenfdev/hr-sample-app/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248943456,"owners_count":21186958,"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":[],"created_at":"2024-10-15T15:46:51.164Z","updated_at":"2025-04-14T19:08:33.065Z","avatar_url":"https://github.com/kenfdev.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![CI](https://github.com/kenfdev/hr-sample-app/actions/workflows/main.yml/badge.svg)](https://github.com/kenfdev/hr-sample-app/actions/workflows/main.yml)\n# HR sample web application using Oso as AuthZ\n\nA sample web application to show how you can integrate Oso.\n\nHere are some demo Gifs to see how the app looks like:\n- [Login with HR user](assets/oso_demo_hr.gif)\n- [Login with Admin non-HR user](assets/oso_demo_admin.gif)\n- [Login with non-Admin non-HR user](assets/oso_demo_non_admin.gif)\n\nThe stack:\n\n- Server\n  - Node.js(TypeScript) + Express + TypeOrm\n- Client\n  - React\n\n## ER\n![Image](https://i.imgur.com/olrqc9g.png)\n\n## Types of authorization\n\n### Request-level authorization\n\n- A request is authorized if it includes a `x-user-id` HTTP Header\n  - Otherwise, `401` will be returned\n\n### Resource-level authorization\n\n- If the logged-in user is\n  - a member of the HR department\n    - the user\n      - can view all the members of the organization\n      - can edit all the members of the organization\n  - not a member of the HR department\n    - the user\n      - can view members which belong to the same department\n  - an admin user\n    - the user\n      - can use the admin features of the service (can be accessed from the user menu)\n\n### Field-level authorization\n\n- If the logged-in user is\n  - a member of the HR department\n    - the user\n      - can view all the members' fields including private fields (such as salary)\n      - can edit all the updatable fields including private fields (such as salary) \n  - not a member of the HR department\n    - the user\n      - can view other members' public fields only\n      - can view private fields of the logged in user\n      - can edit public fields of the logged in user (not private fields such as salary)\n\n## Architecture Overview\n\n![Image](https://i.imgur.com/X1K9gIc.png)\n\nBasically:\n1. The UseCaseController receives a request\n2. The UseCaseController invokes the UseCaseService's method\n   1. The UseCaseService invokes the UseCaseRepository to fetch data\n      1. The UseCaseRepository fetches data from SQLite (Calls the DataFilter if filtering is necessary)\n   2. The UseCaseService enforces field-level authorization and returns results to the UseCaseController\n3. The UseCaseController sends the response to the requester\n\n### Why use 2 Oso instances?\n\nThis example creates 2 Oso instances:\n\n* 1 for the ORM models\n* 1 for the Core models\n\nThis is required because the ORM models' field names differ from the Core models. For example, the [MemberOrm](./server/src/members/shared/typeorm/memberOrm.ts) model has a `departmentId` fields but the [Member](./server/src/members/shared/member.ts) model does not. Hence, the Polar differs:\n\nThe ORM Polar:\n\n```sh\nhas_permission(user: User, \"read\", member: Member) if\n  user.member.department.id = member.departmentId or\n  user.member.department.name = \"hr\";\n```\n\nThe Core Polar:\n\n```sh\nhas_permission(user: User, \"read\", member: Member) if\n  user.memberInfo.department.id = member.department.id or\n  user.memberInfo.department.name = \"hr\";\n```\n\nLook how the field names `user.member` and `user.memberInfo` differ. You can rename the Core models to use `user.member`, but, imo field names shouldn't depend on tools and frameworks. They should be isolated.\n\n### Where Oso is used\n\n#### Data filtering\n\n**authorizedQuery**\n\nYou can see the [authorizedQuery](https://docs.osohq.com/node/guides/data_filtering.html) being used in [repository implementations](https://github.com/kenfdev/hr-sample-app/blob/422bc189b010d8896f3fef04b726392453b1d1ef/server/src/members/list-all-members/repository/listAllMembersSqliteRepository.ts#L21). By using the `authorizedQuery` you can add more query options such as sort.\n\n**authorizedFields**\n\n[authorizedFields](https://docs.osohq.com/node/reference/api/classes/oso.oso-1.html#authorizedfields) can be found in UseCaseServices. It is used to [authorize request bodies](https://github.com/kenfdev/hr-sample-app/blob/422bc189b010d8896f3fef04b726392453b1d1ef/server/src/members/edit-member-detail/editMemberDetailService.ts#L30-L34) when there is a mutation request such as PATCHES.\n\n**authorizedActions**\n\n[authorizedActions](https://docs.osohq.com/node/reference/api/classes/oso.oso-1.html#authorizedactions) can be found in UseCaseServices. It is used to [check if the requester has permission to do an action to a specific resource](https://github.com/kenfdev/hr-sample-app/blob/422bc189b010d8896f3fef04b726392453b1d1ef/server/src/members/show-member-detail/showMemberDetailService.ts#L40-L50) (e.g. can the user update the resource?)\n\n## How to start\n\n### Server\n\n```sh\ncd server\n\n# install dependencies\nnpm install\n\n# seed the SQLite database\nnpm run seed:refresh\n\n# start the server\nnpm run dev\n```\n\n### Client\n\n```sh\ncd client\n\n# install dependencies\nnpm install\n\n# start the front-end locally\nnpm start\n```\n\n### Start playing around\n\nAccess http://localhost:3000/login and you'll see a page like the one below:\n![Image](https://i.imgur.com/u58mPWf.png)\n\nSelect a user and you will be logged in as the selected user for further requests.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkenfdev%2Fhr-sample-app","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkenfdev%2Fhr-sample-app","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkenfdev%2Fhr-sample-app/lists"}