{"id":18715102,"url":"https://github.com/cerbos/express-okta-cerbos","last_synced_at":"2026-03-27T03:43:12.990Z","repository":{"id":42557371,"uuid":"436300489","full_name":"cerbos/express-okta-cerbos","owner":"cerbos","description":"An example stack of integrating Cerbos with an Express server using Okta for authentication and user management.","archived":false,"fork":false,"pushed_at":"2025-04-07T02:04:26.000Z","size":1241,"stargazers_count":5,"open_issues_count":5,"forks_count":3,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-12T13:06:53.097Z","etag":null,"topics":["authentication","authorization","cerbos","express","node","otka"],"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/cerbos.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":"2021-12-08T15:38:35.000Z","updated_at":"2025-02-17T07:28:57.000Z","dependencies_parsed_at":"2023-12-04T05:27:16.194Z","dependency_job_id":"cca8ed48-c5f0-45c1-955f-19c797b4c96f","html_url":"https://github.com/cerbos/express-okta-cerbos","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/cerbos%2Fexpress-okta-cerbos","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cerbos%2Fexpress-okta-cerbos/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cerbos%2Fexpress-okta-cerbos/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cerbos%2Fexpress-okta-cerbos/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cerbos","download_url":"https://codeload.github.com/cerbos/express-okta-cerbos/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248571896,"owners_count":21126522,"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":["authentication","authorization","cerbos","express","node","otka"],"created_at":"2024-11-07T13:07:35.397Z","updated_at":"2026-03-27T03:43:12.877Z","avatar_url":"https://github.com/cerbos.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# express-okta-cerbos\n\nAn example stack of integrating [Cerbos](https://cerbos.dev) with an [Express](https://expressjs.com/) server using [Okta](https://okta.com) for authentication and user management.\n\n## Dependencies\n\n- Okta account\n- Node\n\n\u003e For simplicity this demo is using the hosted Cerbos Demo PDP avaliable in the Playground so running the Cerbos container locally isn't required. For production use cases a deployed Cerbos PDP is required and the code updated to point to your instance. You can read more about the deployment options [here](https://docs.cerbos.dev/cerbos/latest/deployment/index.html).\n\n\n## Setup\n\n### Install Deps\n\nClone this repoo and run `npm install`\n\n### Create an Okta Application\n\nIn your Okta instance you need to create a new application. For this example we will be making use of Okta's ExpressOIDC package so the application's sign-in method needs to be `OIDC - OpenID Connect` and the application type is `Web Application`.\n\n\u003cimg src=\"docs/okta-create-app.png\" /\u003e\n\n### Set Redirect URLs\n\nThe default redirect URLs for sign-in and sign-out are correct if you are running this demo app on the default 8080 port. If you have chanaged this in your `.env` file then you will need to update accordingly.\n\n\u003cimg src=\"docs/okta-app-settings.png\" /\u003e\n\n### Enabling Groups in the Okta Token\n\nBy default the groups the user belongs to are not passed to the application in the Okta token - this needs enabling as these groups will be passed from Okta to Cerbos for use in authorization decisions.\n\nTo do this, goto _Security \u003e API_ in the sidebar, and edit the default _Authorization Server_.\n\nOn this page, got the _Claims_ tab and press _Add Claim_. Add a new claim called groups which includes the groups of the user in the ID token.\n\n\u003cimg src=\"docs/okta-groups-claim.png\"\u003e\n\n\u003e In production you will likely want to filter this down, but for this example we are enabling all groups to be added to the token.\n\n### Create an example `admin` group.\n\nIn a new Okta account the only group that exists is the _Everyone_ group. For our demo application policies we expect users to be in `admin` or `user` group as this is what is checked.\n\nUnder _Directory \u003e Groups_ press _Add Group_ and create the two groups and add your example users to them.\n\n\n### Setup Environment Variables\n\nMake a copy of the `.env.sample` file and call it `.env`. You will then need to populate the feilds that begin with `OKTA_` with the information provided in the new application you created.\n\n```\nPORT=8080\nCERBOS_HOSTNAME=https://demo-pdp.cerbos.cloud\nCERBOS_PLAYGROUND=ygW612cc9c9xXOsOZjI40ovY2LZvXf43\nOKTA_DOMAIN=\nOKTA_CLIENTID=\nOKTA_CLIENTSECRET=\nOKTA_APP_BASE_URL=http://localhost:8080\n```\n\n\u003eThis example is using the hosted Demo PDP of Cerbos and an example Playground instance. If you are running your own Cerbos PDP then update the `CERBOS_HOSTNAME` feild to your own instance and remove the `CERBOS_PLAYGROUND` feild.\n\n### Test the app\n\nNow that everything is wired up you should be able to goto [`http://localhost:8080`](http://localhost:8080) and press the login link to authenticate with your Okta account.\n\n## Policies\n\nThis example has a simple CRUD policy in place for a resource kind of `contact` - like a CRM system would have. Should you wish to experiment with this policy, you can \u003ca href=\"https://play.cerbos.dev/p/sZC611cf06deexP0q8CTcVufTVau1SA3\" target=\"_blank\"\u003etry it in the Cerbos Playground\u003c/a\u003e.\n\n\u003ca href=\"https://play.cerbos.dev/p/sZC611cf06deexP0q8CTcVufTVau1SA3\" target=\"_blank\"\u003e\u003cimg src=\"docs/launch.jpg\" height=\"48\" /\u003e\u003c/a\u003e\n\nThe policy expects one of two roles to be set on the principal - `admin` and `user`. These roles are authorized as follows:\n\n| Action | User     | Admin |\n| ------ | -------- | ----- |\n| list   | Y        | Y     |\n| read   | Y        | Y     |\n| create | Y        | Y     |\n| update | If owner | Y     |\n| delete | If owner | Y     |\n\n\n## Request Flow\n\n1. User access the application and clicks `Login`\n2. User is directed to the Okta UI and authenticates\n3. A token is returned back in the redirect URL to the application\n4. That token is then exchanged for the user profile information\n5. The user profile from Okta being stored (user Id, roles etc).\n6. Any requests to the `/contacts` endpoints fetch the data required about the resource being accessed from the data store\n7. Call the Cerbos PDP with the principal, resource and action to check the authorization and then return an error if the user is not authorized. The [Cerbos package](https://www.npmjs.com/package/cerbos) is used for this.\n\n```js\nconst allowed = await cerbos.check({\n  principal: { //pass in the Okta user ID and groups\n    id: req.userContext.userinfo.sub,\n    roles: req.userContext.userinfo.groups,\n  },\n  resource: {\n    kind: \"contact\",\n    instances: {\n      //a map of the resource(s) being accessed\n      [contact.id]: {\n        attr: contact,\n      },\n    },\n  },\n  actions: [\"read\"], //the list of actions being performed\n});\n\n// not authorized for read action\nif (!allowed.isAuthorized(contact.id, \"read\")) {\n  return res.status(403).json({ error: \"Unauthorized\" });\n}\n```\nImplementation at this stage will be dependant on your business requirements.\n\n## Resources\n* [Try online with the Cerbos playground](https://play.cerbos.dev)\n* [Explore demo repositories](https://github.com/cerbos)\n* [Read the documentation](https://docs.cerbos.dev)\n* [Subscribe to our newsletter](https://cerbos.dev/subscribe)\n* [Join the community on Slack](http://go.cerbos.io/slack)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcerbos%2Fexpress-okta-cerbos","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcerbos%2Fexpress-okta-cerbos","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcerbos%2Fexpress-okta-cerbos/lists"}