{"id":15063785,"url":"https://github.com/intricate/paseto-haskell","last_synced_at":"2025-04-10T11:25:41.576Z","repository":{"id":257502000,"uuid":"858462506","full_name":"intricate/paseto-haskell","owner":"intricate","description":"A Haskell implementation of PASETO (Platform-Agnostic Security Tokens).","archived":false,"fork":false,"pushed_at":"2025-02-07T15:15:13.000Z","size":187,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-24T10:12:05.876Z","etag":null,"topics":["cryptography","haskell","jwt","paseto","security","token"],"latest_commit_sha":null,"homepage":"https://hackage.haskell.org/package/paseto","language":"Haskell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/intricate.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":"2024-09-16T23:57:34.000Z","updated_at":"2025-02-07T15:15:13.000Z","dependencies_parsed_at":"2025-02-07T16:22:18.813Z","dependency_job_id":"f85bd096-f3d9-462c-ad6b-a7078de03903","html_url":"https://github.com/intricate/paseto-haskell","commit_stats":null,"previous_names":["intricate/paseto-haskell"],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/intricate%2Fpaseto-haskell","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/intricate%2Fpaseto-haskell/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/intricate%2Fpaseto-haskell/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/intricate%2Fpaseto-haskell/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/intricate","download_url":"https://codeload.github.com/intricate/paseto-haskell/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248208620,"owners_count":21065203,"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":["cryptography","haskell","jwt","paseto","security","token"],"created_at":"2024-09-25T00:07:12.652Z","updated_at":"2025-04-10T11:25:41.557Z","avatar_url":"https://github.com/intricate.png","language":"Haskell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# paseto-haskell\n\nA Haskell implementation of\n[PASETO (**P**latform-**A**gnostic **SE**curity **TO**kens)](https://paseto.io/).\n\n## What is PASETO?\n\nPASETO is everything you love about JOSE (JWT, JWE, JWS) without any of the\n[many design deficits that plague the JOSE standards](https://paragonie.com/blog/2017/03/jwt-json-web-tokens-is-bad-standard-that-everyone-should-avoid).\n\n## Supported PASETO Versions\n\n|          |  v1  |  v2  |  v3  |  v4  |\n| ---------| ---- | ---- | ---- | ---- |\n| `local`  |  ❌  |  ❌  |  ✅  |  ✅  |\n| `public` |  ❌  |  ❌  |  ✅  |  ✅  |\n\nThis library supports PASETO versions\n[3](https://github.com/paseto-standard/paseto-spec/blob/af79f25908227555404e7462ccdd8ce106049469/docs/01-Protocol-Versions/Version3.md)\nand\n[4](https://github.com/paseto-standard/paseto-spec/blob/af79f25908227555404e7462ccdd8ce106049469/docs/01-Protocol-Versions/Version4.md)\nalong with both purposes (`local` and `public`).\n\nSince versions\n[1](https://github.com/paseto-standard/paseto-spec/blob/af79f25908227555404e7462ccdd8ce106049469/docs/01-Protocol-Versions/Version1.md)\nand\n[2](https://github.com/paseto-standard/paseto-spec/blob/af79f25908227555404e7462ccdd8ce106049469/docs/01-Protocol-Versions/Version2.md)\nare deprecated, there is no plan to support them.\n\n## Usage\n\nFor most use cases, it should be sufficient to import the `Crypto.Paseto`\nmodule, which just re-exports types and functions from other modules\nunder `Crypto.Paseto.*`.\n\nHowever, there are some types and functions which aren't re-exported. So, if\nyou need access to any of those, you can import them from their respective\nmodules under `Crypto.Paseto.*`.\n\n### Generating keys\n\n```haskell\n-- Generate symmetric keys\nsymmetricKeyV3 \u003c- generateSymmetricKeyV3\nsymmetricKeyV4 \u003c- generateSymmetricKeyV4\n\n-- Generate signing keys\nsigningKeyV3 \u003c- generateSigningKeyV3\nsigningKeyV4 \u003c- generateSigningKeyV4\n\n-- Construct verification keys from signing keys\nverificationKeyV3 \u003c- fromSigningKey signingKeyV3\nverificationKeyV4 \u003c- fromSigningKey signingKeyV4\n```\n\n### Building tokens\n\nExample of building a V3 public PASETO token with some default claims:\n\n```haskell\n-- Read the signing key from a file\nsigningKeyBs \u003c- BS.readFile \"./signing-key-v3.bin\"\nsigningKey \u003c-\n  case bytesToSigningKeyV3 signingKeyBs of\n    Left err -\u003e error \"invalid signing key\"\n    Right key -\u003e pure key\n\n-- Get some default parameters for building the token\ndefaultParams \u003c- getDefaultBuildTokenParams\n\n-- Add a footer and implicit assertion to the build parameters\nlet params =\n      defaultParams\n        { btpFooter = Footer \"1337 footer\"\n        , btpImplicitAssertion = ImplicitAssertion \"1337 implicit assertion\"\n        }\n\n-- Build the token\nbuildResult \u003c- runExceptT (buildTokenV3Public params signingKey)\n\ncase buildResult of\n  Left err -\u003e error \"failed to build token\"\n  Right token -\u003e ...\n```\n\nWith the default build parameters, this token will have the following claims:\n\n- An `exp` claim of 1 hour from the current system time.\n- An `iat` claim of the current system time.\n- A `nbf` claim of the current system time.\n\n### Decoding tokens\n\nExample of decoding a V4 local PASETO token:\n\n```haskell\n-- Get some default validation rules\ndefaultRules \u003c- getDefaultValidationRules\n\n-- Add another validation rule to check that the token issuer is\n-- \"paragonie.com\"\nlet rules :: [ValidationRules]\n    rules = issuedBy (Issuer \"paragonie.com\") : defaultRules\n\n-- Decode, cryptographically verify, and validate the token\nlet decodeResult =\n      decodeTokenV4Local\n        symmetricKey\n        rules\n        (Just $ Footer \"footer\")\n        Nothing -- no implicit assertion\n        tokenTxt\n\ncase decodeResult of\n  Left err -\u003e error \"invalid token\"\n  Right ValidatedToken { vtToken, vtClaims } -\u003e ...\n```\n\n### Claims\n\nThe `Claims` container API is not re-exported from `Crypto.Paseto` since it\ncontains functions which may conflict with those in `Prelude` and other\ncontainer implementations such as `Data.Map`.\n\nSo you'll need to import:\n\n```haskell\n-- It isn't necessary for this to be qualified; just a recommendation.\nimport qualified Crypto.Paseto.Token.Claims as Claims\n```\n\n#### Constructing claims\n\n```haskell\n-- Empty collection of claims\nClaims.empty\n\n-- Collection of claims consisting of a single element\nClaims.singleton (IssuerClaim $ Issuer \"paragonie.com\")\n\n-- Constructing a collection of claims from a list\nClaims.fromList\n  [ IssuerClaim (Issuer \"paragonie.com\")\n  , SubjectClaim (Subject \"test\")\n  , TokenIdentifierClaim (TokenIdentifier \"87IFSGFgPNtQNNuw0AtuLttPYFfYwOkjhqdWcLoYQHvL\")\n  ]\n\n-- Inserting a claim into an existing collection of claims\nClaims.insert (SubjectClaim $ Subject \"subject\") claims\n```\n\n#### Querying claims\n\n```haskell\n-- For example, looking up the issuer claim\ncase Claims.lookupIssuer claims of\n  Nothing -\u003e error \"issuer claim does not exist\"\n  Just issuer -\u003e ...\n```\n\n#### Custom claims\n\nIt's also possible to construct custom claims (i.e. claims that are not\n[registered/reserved for use within PASETO](https://github.com/paseto-standard/paseto-spec/blob/af79f25908227555404e7462ccdd8ce106049469/docs/02-Implementation-Guide/04-Claims.md#registered-claims)).\n\nNote that it's acceptable to store any kind of JSON data within a custom\nclaim.\n\n```haskell\n-- Construct the custom claim's key\ncustomClaimKey \u003c-\n  case mkUnregisteredClaimKey \"customData\" of\n    Nothing -\u003e error \"invalid custom claim key\"\n    Just k -\u003e pure k\n\n-- Construct the custom claim\nlet customClaim :: Claim\n    customClaim = CustomClaim customClaimKey (Aeson.String \"customValue\")\n\n-- Now you can utilize it like any other 'Claim'. For example:\nlet claims :: Claims\n    claims = Claims.singleton customClaim\n```\n\nIf you attempt to pass a registered/reserved claim key to\n`mkUnregisteredClaimKey`, it will return `Nothing`:\n\n```haskell\n-- For example, this will return 'Nothing':\nmkUnregisteredClaimKey \"iss\"\n```\n\n### Validation\n\nAs seen in the [token decoding example above](#decoding-tokens), you can\nconstruct a list of recommended default validation rules using\n`getDefaultValidationRules`. At the moment, the default rules check that:\n\n- The `exp` claim is not in the past.\n- The `iat` claim is not in the future.\n- The `nbf` claim is not in the future.\n\nThere are also some other simple pre-defined rules that you can utilize. For\nexample:\n\n- `forAudience`\n- `identifiedBy`\n- `issuedBy`\n- `notExpired`\n- `subject`\n- `validAt`\n\nIf this is insufficient for your use case, you can also construct your own\ncustom validation rules:\n\n```haskell\nlet f :: Claims -\u003e Either ValidationError ()\n    f claims =\n      if isSomethingValid claims\n        then Right ()\n        else Left (ValidationCustomError \"something was invalid, bro\")\n\n    customRule :: ValidationRule\n    customRule = ValidationRule f\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fintricate%2Fpaseto-haskell","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fintricate%2Fpaseto-haskell","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fintricate%2Fpaseto-haskell/lists"}