{"id":18324716,"url":"https://github.com/tchoutri/biscuit-demo","last_synced_at":"2025-04-09T15:15:44.529Z","repository":{"id":118115583,"uuid":"569679781","full_name":"tchoutri/biscuit-demo","owner":"tchoutri","description":null,"archived":false,"fork":false,"pushed_at":"2022-11-23T11:30:07.000Z","size":19,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-09T15:15:40.420Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Haskell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tchoutri.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}},"created_at":"2022-11-23T11:27:39.000Z","updated_at":"2022-11-23T11:28:16.000Z","dependencies_parsed_at":null,"dependency_job_id":"3ac0b580-ae8c-4b28-a39e-ad06aae0b71b","html_url":"https://github.com/tchoutri/biscuit-demo","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/tchoutri%2Fbiscuit-demo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tchoutri%2Fbiscuit-demo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tchoutri%2Fbiscuit-demo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tchoutri%2Fbiscuit-demo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tchoutri","download_url":"https://codeload.github.com/tchoutri/biscuit-demo/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248055276,"owners_count":21040157,"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-11-05T18:35:36.913Z","updated_at":"2025-04-09T15:15:44.509Z","avatar_url":"https://github.com/tchoutri.png","language":"Haskell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Biscuit demo\n\nThis repository is a showcase for the [Biscuit](https://biscuitsec.org) authorization token system.\n\nThree services are contained in this project:\n\n* The token dispenser, that will send a token to the client based on email;\n* The API server, that will proces requests from the client\n\n## Demo\n\nStart the services:\n\n```bash\n$ cabal run dispenser\n\n[+] Starting the Token dispenser on http://localhost:8900\n\n$ cabal run api-server\n\n[+] Starting the API server on http://localhost:8902\n```\n\nThen get the token from the dispenser with this command (using [httpie](https://httpie.io)):\n\n```bash\n$ http POST http://localhost:8900/tokens email=admin@example.org              \nHTTP/1.1 200 OK\nContent-Type: application/json;charset=utf-8\nDate: Fri, 11 Mar 2022 10:06:22 GMT\nServer: Warp/3.3.20\nTransfer-Encoding: chunked\n\n{\n    \"token\": \"EqECCrYBCiQ1ZGQ5OGIzNy0wMWRmLTQ0YWQtOGEzYi0yZDg2YjU4MDUzYjEKJGFiNTNlN2ViLTdmZjItNDM4ZC1iNGRiLTBjZDEwMTNkOWE2OAoDYXBpCgRyZWFkCgdzZXJ2aWNlCgp1c2VyX2dyb3VwCgd1c2VyX2lkCgV3cml0ZRgCIggKBggNEgIYCCIQCg4IBBICGAoSAhgMEgIYByIQCg4IBBICGA4SAhgMEgIYByIICgYICxICGAkSJAgAEiC-S8ZXcwjZK0AVM3hFHkdWGr1x1WKa57rM76ERm84m0hpAm79G03LibmVHX9UOAW4g12i6XfU3dwmSge4Xn1cNM7z-3d2TkT4C_oBipJE-L_d4CgaUjAb17Qm3pe22L9NmDyIiCiCzUfLfQJGOlrLJ0NOM8eW3EUG7Ul4EhciUFeLes38MuA==\"\n}\n```\n\nput this token in an environment variable, aptly named `$biscuit`:\n\n```bash\n\n$ export biscuit=\"EqECCrYBCiQ1ZGQ5OGIzNy0wMWRmLTQ0YWQtOGEzYi0yZDg2YjU4MDUzYjEKJGFiNTNlN2ViLTdmZjItNDM4ZC1iNGRiLTBjZDEwMTNkOWE2OAoDYXBpCgRyZWFkCgdzZXJ2aWNlCgp1c2VyX2dyb3VwCgd1c2VyX2lkCgV3cml0ZRgCIggKBggNEgIYCCIQCg4IBBICGAoSAhgMEgIYByIQCg4IBBICGA4SAhgMEgIYByIICgYICxICGAkSJAgAEiC-S8ZXcwjZK0AVM3hFHkdWGr1x1WKa57rM76ERm84m0hpAm79G03LibmVHX9UOAW4g12i6XfU3dwmSge4Xn1cNM7z-3d2TkT4C_oBipJE-L_d4CgaUjAb17Qm3pe22L9NmDyIiCiCzUfLfQJGOlrLJ0NOM8eW3EUG7Ul4EhciUFeLes38MuA==\"\n```\n\nand now let's query the API server:\n\n```bash\n$ http GET \"http://localhost:8902/user_groups/5dd98b37-01df-44ad-8a3b-2d86b58053b1\" \"Authorization:Bearer $biscuit\"\nHTTP/1.1 200 OK\nContent-Type: application/json;charset=utf-8\nDate: Fri, 11 Mar 2022 10:08:36 GMT\nServer: Warp/3.3.20\nTransfer-Encoding: chunked\n\n{\n    \"name\": \"Passing the time\",\n    \"userGroupId\": \"5dd98b37-01df-44ad-8a3b-2d86b58053b1\"\n}\n```\n\nWe can see that the biscuit was validated and the checks have passed.\n\nNow, what if someone from HR tries to access a UserGroup?\n\nAfter retrieving a token from the dispenser with the email \"hr@example.org\", we try and query the API server:\n\n```bash\nhttp GET \"http://localhost:8902/user_groups/5dd98b37-01df-44ad-8a3b-2d86b58053b1\" \"Authorization:Bearer $hr_biscuit\"\nHTTP/1.1 401 Unauthorized\nDate: Fri, 11 Mar 2022 10:23:46 GMT\nServer: Warp/3.3.20\nTransfer-Encoding: chunked\n\nBiscuit failed checks\n```\n\nAnd in the server logs:\n\n```haskell\nResultError (NoPoliciesMatched [[QueryItem {qBody = [Predicate {name = \"service\", terms = [LString \"peopledoc\"]}], qExpressions = []}],[QueryItem {qBody = [Predicate {name = \"service\", terms = [LString \"api\"]}], qExpressions = []}]])\n```\n\nThis is a bit rough to read, but look for the \"service\" strings in this message. The first one is \"peopledoc\", which is the value of the `service()` fact\nin the HR token. The other one is \"api\", which is the value expected by the API server. They do not match, and as such, the verification fails.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftchoutri%2Fbiscuit-demo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftchoutri%2Fbiscuit-demo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftchoutri%2Fbiscuit-demo/lists"}