{"id":22268208,"url":"https://github.com/curityio/kafka-zero-trust","last_synced_at":"2026-03-12T06:39:45.376Z","repository":{"id":74437537,"uuid":"476235364","full_name":"curityio/kafka-zero-trust","owner":"curityio","description":"OAuth 2.0 zero trust event based messaging between APIs","archived":false,"fork":false,"pushed_at":"2025-01-20T17:21:51.000Z","size":3211,"stargazers_count":3,"open_issues_count":0,"forks_count":2,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-12-13T05:38:10.471Z","etag":null,"topics":["api","code-example","events","kafka","nodejs","oauth2","zero-trust"],"latest_commit_sha":null,"homepage":"https://curity.io/resources/learn/zero-trust-api-events/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/curityio.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2022-03-31T09:21:36.000Z","updated_at":"2025-02-27T11:09:26.000Z","dependencies_parsed_at":"2025-10-13T14:30:50.992Z","dependency_job_id":"6a1df731-d46c-42a7-8bfe-b9bd49631870","html_url":"https://github.com/curityio/kafka-zero-trust","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/curityio/kafka-zero-trust","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/curityio%2Fkafka-zero-trust","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/curityio%2Fkafka-zero-trust/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/curityio%2Fkafka-zero-trust/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/curityio%2Fkafka-zero-trust/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/curityio","download_url":"https://codeload.github.com/curityio/kafka-zero-trust/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/curityio%2Fkafka-zero-trust/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30417530,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-12T04:41:02.746Z","status":"ssl_error","status_checked_at":"2026-03-12T04:40:12.571Z","response_time":114,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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","code-example","events","kafka","nodejs","oauth2","zero-trust"],"created_at":"2024-12-03T11:11:54.172Z","updated_at":"2026-03-12T06:39:45.355Z","avatar_url":"https://github.com/curityio.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Kafka Zero Trust\n\nA project to demonstrate event based messaging between APIs with zero trust:\n\n- Publishing APIs include a long lived reduced privilege access token in event messages.\n- Consuming APIs validate the access token before processing event messages.\n- User identity and other secure values flows securely between async APIs.\n\nThis code example uses [Apache Kafka](https://kafka.apache.org/) for event based messaging.\n\n## Behavior Overview\n\nTo demonstrate the approach, the code example uses a flow where a user facing app triggers a purchase.\\\nThe user facing app calls an Orders API which publishes an event to a message broker.\\\nAn Invoices API then consumes the event and makes additional security checks before processing the data.\\\nThe following diagram illustrates the components involved and the key behaviors:\n\n![Components](./doc/end-to-end-flow.svg)\n\n## Prerequisites\n\nThe solution provides two simple Node.js microservices and some deployment resources.\\\nFirst ensure that these prerequisites are installed:\n\n- [Docker](https://www.docker.com/products/docker-desktop/)\n- [Node.js 20 or higher](https://nodejs.org/en/download/)\n\nAlso get a `license.json` file for the Curity Identity Server and copy it to the `idsvr` folder:\n\n- If required sign up to the [Curity Developer Portal](https://developer.curity.io/) with your Github account\n- You can get a [Free Community Edition License](https://curity.io/product/community/) if you are new to the Curity Identity Server\n\n## Run the Code\n\nExecute these commands to run the APIs locally and all other components in a Docker Compose network.\\\nOn the initial run it will take some minutes to download all third party containers:\n\n```bash\n./build.sh\n./deploy.sh\n```\n\nThen run a minimal console client which acts as the user facing app:\n\n```bash\ncd console-client\nnpm install\nnpm start\n```\n\nThe client will run a code flow that opens the system browser.\\\nSign in as `demouser / Password1` to get the initial user level access token:\n\n![Login](./doc/login.png)\n\nThe console client then simply calls the Orders API to create an order transaction and exits.\\\nMeanwhile the Orders API raises a secure event consumed at a later time by the Invoices API.\n\n## URLs\n\nThe following external URLs are available on the development computer.\\\nThe Invoices API and Apache Kafka run inside the cluster.\n\n| Component | Location |\n| --------- | -------- |\n| API Gateway | http://localhost:3000 |\n| Orders API | http://localhost:3000/orders |\n| Curity Identity Server Runtime | http://localhost:8443 |\n| Curity Identity Server Admin UI | http://localhost:6749 |\n\n## Data and Identity Flow\n\nThe client application sends an example order request to the Orders API.\\\nThe Orders API calculates prices and saves the transaction in its own data as follows:\n\n```json\n{\n  \"transactionID\": \"6b69df74-339f-416b-84bb-f1f4f32d8f1a\",\n  \"userID\": \"demouser\",\n  \"utcTime\": \"2025-01-06T09:01:12.405Z\",\n  \"items\": [\n    {\n      \"itemID\": 1,\n      \"quantity\": 1,\n      \"price\": 100\n    },\n    {\n      \"itemID\": 3,\n      \"quantity\": 3,\n      \"price\": 100\n    }\n  ]\n}\n```\n\nThe Orders API then performs a token exchange and publishes an `OrderCreated` event with the following structure.\\\nA long lived access token that contains the `userID` and `transactionID` is included in the event message's headers:\n\n```json\n{\n  \"eventID\": \"e80be47d-7282-4f3c-898a-709ca5393aa5\",\n  \"utcTime\": \"2025-01-02T10:23:56.258Z\",\n  \"items\": [\n    {\n      \"itemID\": 1,\n      \"quantity\": 1,\n      \"price\": 100\n    },\n    {\n      \"itemID\": 3,\n      \"quantity\": 3,\n      \"price\": 100\n    }\n  ]\n}\n```\n\nThe Invoices API consumes the event and validates the JWT access token before processing it.\\\nThe Invoices API then saves the transaction in its own data in the following format:\n\n```json\n{\n  \"invoiceID\": \"43f99a41-f50b-443d-813f-3f5eee21851b\",\n  \"transactionID\": \"0d2e8437-d4e3-40e1-8d6e-a6e17d2c04c7\",\n  \"userID\": \"demouser\",\n  \"utcTime\": \"2025-01-06T09:01:13.686Z\",\n  \"amount\": 400\n}\n```\n\n## Security and Tokens\n\nThe client gets a normal access token with a 15 minute expiry similar to the following example.\\\nThe audience and scope allows the token to be sent to the Orders API.\n\n```json\n{\n  \"jti\": \"3ed02b8d-503d-46f1-bffa-e38d30a4c9d3\",\n  \"delegationId\": \"9dd15191-9441-4056-9e56-52b7ad116b18\",\n  \"exp\": 1736154372,\n  \"nbf\": 1736154072,\n  \"scope\": \"openid profile orders\",\n  \"iss\": \"http://localhost:8443/oauth/v2/oauth-anonymous\",\n  \"sub\": \"demouser\",\n  \"aud\": \"api.example.com\",\n  \"iat\": 1736154072,\n  \"purpose\": \"access_token\"\n}\n```\n\nThe Orders API makes a token exchange request with the original access token.\\\nThe Orders API upscopes the token to get a long lived access token with a lifetime of 1 week.\\\nThe token has limited invoicing privileges, sufficient to resume asynchronous processing:\n\n```text\nPOST http://localhost:8443/oauth/v2/oauth-token\n\ngrant_type=urn:ietf:params:oauth:grant-type:token-exchange\n\u0026client_id=orders-api-client\n\u0026client_secret=Password1\n\u0026subject_token=eyJraWQiOiItMTcyNTQxNzE2NyIsIng...\n\u0026subject_token_type=urn:ietf:params:oauth:token-type:access_token\n\u0026scope=trigger_invoicing\n\u0026audience=jobs.example.com\n\u0026transaction_id=6b69df74-339f-416b-84bb-f1f4f32d8f1a\n\u0026event_id=e80be47d-7282-4f3c-898a-709ca5393aa5\n```\n\nThe Invoices API then receives the following JWT access token payload.\\\nThe audience of `jobs.example.com` and the `trigger_invoicing` are only accepted at messaging endpoints.\\\nThe access token is bound to a precise event message and transaction to reduce token privileges.\n\n```json\n{\n  \"jti\": \"14c4ac0c-7806-401b-b6db-94ae1b6f8d4a\",\n  \"delegationId\": \"9dd15191-9441-4056-9e56-52b7ad116b18\",\n  \"exp\": 1736758872,\n  \"nbf\": 1736154072,\n  \"scope\": \"trigger_invoicing\",\n  \"iss\": \"http://localhost:8443/oauth/v2/oauth-anonymous\",\n  \"sub\": \"demouser\",\n  \"aud\": \"jobs.example.com\",\n  \"iat\": 1736154072,\n  \"purpose\": \"access_token\",\n  \"transaction_id\": \"0d2e8437-d4e3-40e1-8d6e-a6e17d2c04c7\",\n  \"event_id\": \"5a704593-6f1f-45e4-886a-e37fe5848dc7\"\n}\n```\n\n## Further Information\n\nSee the following Curity website resources for further details:\n\n- [Zero Trust API Events Article](https://curity.io/resources/learn/zero-trust-api-events)\n- [Kafka Zero Trust Code Example](https://curity.io/resources/learn/securing-api-events-using-jwts)\n\nPlease visit [curity.io](https://curity.io/) for more information about the Curity Identity Server.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcurityio%2Fkafka-zero-trust","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcurityio%2Fkafka-zero-trust","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcurityio%2Fkafka-zero-trust/lists"}