{"id":28503144,"url":"https://github.com/ivarref/encrypted-url-state","last_synced_at":"2025-07-05T12:30:30.921Z","repository":{"id":291960215,"uuid":"979354572","full_name":"ivarref/encrypted-url-state","owner":"ivarref","description":"Encrypted url state. With expiration.","archived":false,"fork":false,"pushed_at":"2025-05-08T07:36:25.000Z","size":11,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-06-08T17:06:41.817Z","etag":null,"topics":["base64","clojure","nippy","url"],"latest_commit_sha":null,"homepage":"","language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"epl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ivarref.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}},"created_at":"2025-05-07T11:40:17.000Z","updated_at":"2025-05-12T07:37:48.000Z","dependencies_parsed_at":"2025-05-07T12:51:36.213Z","dependency_job_id":null,"html_url":"https://github.com/ivarref/encrypted-url-state","commit_stats":null,"previous_names":["ivarref/encrypted-url-state"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ivarref/encrypted-url-state","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ivarref%2Fencrypted-url-state","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ivarref%2Fencrypted-url-state/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ivarref%2Fencrypted-url-state/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ivarref%2Fencrypted-url-state/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ivarref","download_url":"https://codeload.github.com/ivarref/encrypted-url-state/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ivarref%2Fencrypted-url-state/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263741509,"owners_count":23504249,"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":["base64","clojure","nippy","url"],"created_at":"2025-06-08T17:06:05.140Z","updated_at":"2025-07-05T12:30:30.914Z","avatar_url":"https://github.com/ivarref.png","language":"Clojure","funding_links":[],"categories":[],"sub_categories":[],"readme":"# encrypted-url-state\n\nEncrypted url state. With expiration.\n\nEver wanted to store some encrypted state in a URL? Look no further.\n\n## Rationale\n\nYour service sends an end user to an external service for a task.\nThe external service supports custom callback URLs / URL parameters.\n\nYour service does not want to\nstore unnecessary state, so it includes the state it needs to resume\nwork after the task is completed in the callback URL.\n\nAs the state is kept by the external service, a restart to your service will\nnot delete the state.\n\nWhen your service is visited with the callback URL, it can decrypt\nthe state and then use it to resume doing whatever it needs to do.\n\nFor example in a signing process:\n\n```mermaid\nsequenceDiagram\n    enduser-\u003e\u003eyourservice: Login for the first time\n    yourservice-\u003e\u003esignservice: Create signature job. Set callback url state to (eus/encrypt \"my-key\" user-id)\n    yourservice-\u003e\u003eenduser: Redirect to signservice \n    enduser-\u003e\u003esignservice: Signs the document\n    signservice-\u003e\u003eenduser: Redirects back to yourservice with encrypted URL state included\n    enduser-\u003e\u003eyourservice: Visit callback URL with state\n    yourservice-\u003e\u003eyourservice: Decrypts state (user-id) \n    yourservice-\u003e\u003epersistentDB: Marks that user-id has signed the PDF\n    yourservice-\u003e\u003eenduser: Present welcome page\n```\n\n## Installation\n\n```\ncom.github.ivarref/encrypted-url-state {:git/tag \"v0.0.1\" :git/sha \"9aaf5de92e612393062769992353b2321ec38be7\"}\n```\n\n## Usage\n\n```clojure\n(require '[com.github.ivarref.encrypted-url-state :as eus])\n\n; Encrypt:\n(eus/encrypt \"my-key\" \"my-state\") ; Default expiry: 3600 seconds (1 hour) from now\n=\u003e \"TlBZDrDCzqg7goKQvpijViGM2_jEZEJqFk1Gcqibt5W64UzQLfYvbLnATi8TqUYuwg==\"\n\n; Explicit expiry given as epoch time in seconds: 24 hours from now\n(eus/encrypt \"my-key\"\n             (eus/curr-epoch-time-plus-seconds (* 24 3600))\n             \"my-state\")\n=\u003e \"TlBZDtz_UPYPEal6qmk-ACMUogigcP01wMZc_UWdg60fN6YHdmkrhfM9m7FH3wVlEw==\"\n\n\n; Decrypt:\n; Default epoch time: (long (/ (System/currentTimeMillis) 1000))\n(eus/decrypt \"my-key\" *1) \n=\u003e {:expired? false, :state \"my-state\", :error? false, :error-message nil}\n\n; Explicit epoch time:\n(eus/decrypt \"my-key\"\n             1746604368\n             \"TlBZDtz_UPYPEal6qmk-ACMUogigcP01wMZc_UWdg60fN6YHdmkrhfM9m7FH3wVlEw==\") \n=\u003e {:expired? false, :state \"my-state\", :error? false, :error-message nil}\n\n; :error? will be true if a tamper attempt was detected:\n; :error-message will be set to the message of the exception\n(eus/decrypt \"my-key\" (eus/encrypt \"attacker-key\" \"my-state\"))\n=\u003e {:expired? false,\n    :state nil, \n    :error? true,\n    :error-message \"Thaw failed. Possible decryption/decompression error, unfrozen/damaged data, etc.\"}\n\n; :expired? will be true if the message was expired:\n(eus/decrypt \"my-key\"\n             (eus/curr-epoch-time-plus-seconds 3601) ; one second too old!\n             (eus/encrypt \"my-key\" \"my-state\"))\n=\u003e {:expired? true, :state nil, :error? false, :error-message \"Expired\"}\n\n\n; Full typical usage:\n(let [input (eus/encrypt \"my-key\" \"my-state\")\n      {:keys [error? expired? state]} (eus/decrypt \"my-key\" input)]\n  (cond error?\n        :call-the-cops ; state will be nil\n\n        expired?\n        :slow-user-alert ; state will be nil\n\n        :else\n        :do-work!))\n```\n\n### Details\n\n`encrypt` and `decrypt` use high-strength AES128, courtesy of [nippy](https://github.com/taoensso/nippy/)*.\nThis yields a smaller amount of bytes than using a regular JWT would. An external user also cannot view\nthe contents of the state as the message is encrypted.\nThere is not any public key here. This means that the recipient of the encrypted state should be the same service\nor another service with an identical private key/password.\n\n### Thanks\n\n* #clojure-norway on [Clojurians](https://clojurians.slack.com).\n* \\*[Peter Taoussanis](https://www.taoensso.com/) for nippy.\n* \\*[Magnar Sveen](https://magnars.com/) for [confair](https://github.com/magnars/confair).\n\n### IFAQ\n\n\u003e Is it worth making a library consisting of only 58 lines of code?\n\nWho knows.\n\n\u003e Why did you make it?\n\nI went down a deep Java Standard Library signing/crypto rabbit hole, \ngot feedback from #clojure-norway, felt the pain of the sunk cost fallacy,\ndeleted most of the code and ultimately just wrapped [nippy](https://github.com/taoensso/nippy/).\n\n\u003e IFAQ?\n\nThat is InFrequently Asked Questions.\n\n## License\n\nCopyright © 2025 Ivar Refsdal\n\nDistributed under the Eclipse Public License either version 2.0 or (at\nyour option) any later version.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fivarref%2Fencrypted-url-state","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fivarref%2Fencrypted-url-state","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fivarref%2Fencrypted-url-state/lists"}