{"id":13408947,"url":"https://github.com/o1egl/paseto","last_synced_at":"2025-05-14T16:15:58.558Z","repository":{"id":44846746,"uuid":"118562222","full_name":"o1egl/paseto","owner":"o1egl","description":"Platform-Agnostic Security Tokens implementation in GO (Golang)","archived":false,"fork":false,"pushed_at":"2023-02-25T01:40:23.000Z","size":94,"stargazers_count":882,"open_issues_count":6,"forks_count":37,"subscribers_count":22,"default_branch":"master","last_synced_at":"2025-04-12T22:17:32.391Z","etag":null,"topics":["auth","authentication","decoder","encoder","go","golang","jwt","microservice","paseto","past","security","soa","token"],"latest_commit_sha":null,"homepage":null,"language":"Go","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/o1egl.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}},"created_at":"2018-01-23T05:27:39.000Z","updated_at":"2025-04-08T15:02:00.000Z","dependencies_parsed_at":"2024-02-06T01:33:14.960Z","dependency_job_id":null,"html_url":"https://github.com/o1egl/paseto","commit_stats":{"total_commits":34,"total_committers":4,"mean_commits":8.5,"dds":0.08823529411764708,"last_synced_commit":"0757ff684e6cd99a5ae7a778f8a5e32364872245"},"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/o1egl%2Fpaseto","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/o1egl%2Fpaseto/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/o1egl%2Fpaseto/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/o1egl%2Fpaseto/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/o1egl","download_url":"https://codeload.github.com/o1egl/paseto/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254179905,"owners_count":22027884,"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":["auth","authentication","decoder","encoder","go","golang","jwt","microservice","paseto","past","security","soa","token"],"created_at":"2024-07-30T20:00:56.818Z","updated_at":"2025-05-14T16:15:58.540Z","avatar_url":"https://github.com/o1egl.png","language":"Go","funding_links":[],"categories":["Authentication and OAuth","身份验证和OAuth","Authentication and Authorization","Libraries","Go","认证和OAuth授权","Uncategorized","soa","Web Framework Hardening"],"sub_categories":["Contents"],"readme":"# Golang implementation of PASETO: Platform-Agnostic Security Tokens\n[![License](http://img.shields.io/:license-mit-blue.svg)](LICENSE)\n[![GoDoc](https://godoc.org/github.com/o1egl/paseto?status.svg)](https://godoc.org/github.com/o1egl/paseto)\n[![Build Status](http://img.shields.io/travis/o1egl/paseto.svg?style=flat-square)](https://travis-ci.org/o1egl/paseto)\n[![Coverage Status](http://img.shields.io/coveralls/o1egl/paseto.svg?style=flat-square)](https://coveralls.io/r/o1egl/paseto)\n[![Go Report Card](https://goreportcard.com/badge/github.com/o1egl/paseto)](https://goreportcard.com/report/github.com/o1egl/paseto)\n\nThis is a 100% compatible pure Go (Golang) implementation of [PASETO](https://paseto.io) tokens.\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# Contents\n* [What is PASETO?](#what-is-paseto)\n  * [Key Differences between PASETO and JWT](#key-differences-between-paseto-and-jwt)\n* [Installation](#installation)\n* [Usage](#usage)\n* [Benchmarks](#benchmarks)\n* [Supported PASETO Versions](#supported-paseto-versions)\n\n# What is PASETO?\n\nPASETO (Platform-Agnostic SEcurity TOkens) is a specification and reference implementation\nfor secure stateless tokens.\n\n## Key Differences between PASETO and JWT\n\nUnlike JSON Web Tokens (JWT), which gives developers more than enough rope with which to\nhang themselves, PASETO only allows secure operations. JWT gives you \"algorithm agility\",\nPASETO gives you \"versioned protocols\". It's incredibly unlikely that you'll be able to\nuse PASETO in [an insecure way](https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries).\n\n\u003e **Caution:** Neither JWT nor PASETO were designed for\n\u003e [stateless session management](http://cryto.net/~joepie91/blog/2016/06/13/stop-using-jwt-for-sessions/).\n\u003e PASETO is suitable for tamper-proof cookies, but cannot prevent replay attacks\n\u003e by itself.\n\n### PASETO\n\n#### PASETO Example 1\n\n```\nv2.local.QAxIpVe-ECVNI1z4xQbm_qQYomyT3h8FtV8bxkz8pBJWkT8f7HtlOpbroPDEZUKop_vaglyp76CzYy375cHmKCW8e1CCkV0Lflu4GTDyXMqQdpZMM1E6OaoQW27gaRSvWBrR3IgbFIa0AkuUFw.UGFyYWdvbiBJbml0aWF0aXZlIEVudGVycHJpc2Vz\n```\n\nThis decodes to:\n\n* Version: `v2`\n* Purpose: `local` (shared-key authenticated encryption)\n* Payload (hex-encoded):\n  ```\n  400c48a557be10254d235cf8c506e6fea418a26c93de1f05b55f1bc64cfca412\n  56913f1fec7b653a96eba0f0c46542a8a7fbda825ca9efa0b3632dfbe5c1e628\n  25bc7b5082915d0b7e5bb81930f25cca9076964c33513a39aa105b6ee06914af\n  581ad1dc881b1486b4024b9417\n  ```\n  * Nonce: `400c48a557be10254d235cf8c506e6fea418a26c93de1f05`\n  * Authentication tag: `6914af581ad1dc881b1486b4024b9417`\n* Decrypted Payload:\n  ```json\n  {\n    \"data\": \"this is a signed message\",\n    \"exp\": \"2039-01-01T00:00:00+00:00\"\n  }\n  ```\n  * Key used in this example (hex-encoded):\n    ```\n    707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f  \n    ``` \n* Footer:\n  ```\n  Paragon Initiative Enterprises\n  ```\n\n#### PASETO Example 2\n\n```\nv2.public.eyJleHAiOiIyMDM5LTAxLTAxVDAwOjAwOjAwKzAwOjAwIiwiZGF0YSI6InRoaXMgaXMgYSBzaWduZWQgbWVzc2FnZSJ91gC7-jCWsN3mv4uJaZxZp0btLJgcyVwL-svJD7f4IHyGteKe3HTLjHYTGHI1MtCqJ-ESDLNoE7otkIzamFskCA\n```\n\nThis decodes to:\n\n* Version: `v2`\n* Purpose: `public` (public-key digital signature)\n* Payload:\n  ```json\n  {\n    \"data\": \"this is a signed message\",\n    \"exp\": \"2039-01-01T00:00:00+00:00\"\n  }\n  ```\n* Signature (hex-encoded):\n  ```\n  d600bbfa3096b0dde6bf8b89699c59a746ed2c981cc95c0bfacbc90fb7f8207c\n  86b5e29edc74cb8c761318723532d0aa27e1120cb36813ba2d908cda985b2408\n  ```\n* Public key (hex-encoded):\n  ```\n  11324397f535562178d53ff538e49d5a162242970556b4edd950c87c7d86648a\n  ```\n\nTo learn what each version means, please see [this page in the documentation](https://github.com/paragonie/paseto/tree/master/docs/01-Protocol-Versions).\n\n### JWT\n\nAn example JWT ([taken from JWT.io](https://jwt.io)) might look like this:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ \n```\n\nThis decodes to:\n\n**Header**:\n```json\n{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n```\n\n**Body**:\n```json\n{\n  \"sub\": \"1234567890\",\n  \"name\": \"John Doe\",\n  \"admin\": true\n}\n```\n\n**Signature**:  \n```\nTJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ\n```\n\n## Motivation \n\nAs you can see, with JWT, you get to specify an `alg` header. There are a lot of options to\nchoose from (including `none`).\n\nThere have been ways to exploit JWT libraries by replacing RS256 with HS256 and using\nthe known public key as the HMAC-SHA256 key, thereby allowing arbitrary token forgery. \n\nWith PASETO, your options are `version` and a `purpose`. There are two possible\nvalues for `purpose`:\n\n* `local` -- shared-key encryption (symmetric-key, [AEAD](https://tonyarcieri.com/all-the-crypto-code-youve-ever-written-is-probably-broken))\n* `public` -- public-key digital signatures (asymmetric-key)\n\nPASETO only allows you to use [authenticated modes](https://tonyarcieri.com/all-the-crypto-code-youve-ever-written-is-probably-broken).\n\nRegardless of the purpose selected, the header (and an optional footer, which is always\ncleartext but base64url-encoded) is included in the signature or authentication tag.\n\n# Installation\n\nTo install the library use the following command:\n\n```\n$ go get -u github.com/o1egl/paseto\n```\n\n# Usage\nThis library contains a predefined JsonToken struct for using as payload, but you are free to use any data types and structs you want.\n\nDuring the encoding process, a payload of type string and []byte is used without transformation. For other data types, the library encodes the payload to JSON.\n\n## Create token using symmetric key (local mode): \n```go\nsymmetricKey := []byte(\"YELLOW SUBMARINE, BLACK WIZARDRY\") // Must be 32 bytes\nnow := time.Now()\nexp := now.Add(24 * time.Hour)\nnbt := now\n\njsonToken := paseto.JSONToken{\n        Audience:   \"test\",\n        Issuer:     \"test_service\",\n        Jti:        \"123\",\n        Subject:    \"test_subject\",\n        IssuedAt:   now,\n        Expiration: exp,\n        NotBefore:  nbt,\n        }\n// Add custom claim    to the token    \njsonToken.Set(\"data\", \"this is a signed message\")\nfooter := \"some footer\"\n\n// Encrypt data\ntoken, err := paseto.Encrypt(symmetricKey, jsonToken, footer)\n// token = \"v2.local.E42A2iMY9SaZVzt-WkCi45_aebky4vbSUJsfG45OcanamwXwieieMjSjUkgsyZzlbYt82miN1xD-X0zEIhLK_RhWUPLZc9nC0shmkkkHS5Exj2zTpdNWhrC5KJRyUrI0cupc5qrctuREFLAvdCgwZBjh1QSgBX74V631fzl1IErGBgnt2LV1aij5W3hw9cXv4gtm_jSwsfee9HZcCE0sgUgAvklJCDO__8v_fTY7i_Regp5ZPa7h0X0m3yf0n4OXY9PRplunUpD9uEsXJ_MTF5gSFR3qE29eCHbJtRt0FFl81x-GCsQ9H9701TzEjGehCC6Bhw.c29tZSBmb290ZXI\"\n\n// Decrypt data\nvar newJsonToken paseto.JSONToken\nvar newFooter string\nerr := paseto.Decrypt(token, symmetricKey, \u0026newJsonToken, \u0026newFooter)\n```\n\n## Create token using asymetric key (public mode): \n```go\nb, _ := hex.DecodeString(\"b4cbfb43df4ce210727d953e4a713307fa19bb7d9f85041438d9e11b942a37741eb9dbbbbc047c03fd70604e0071f0987e16b28b757225c11f00415d0e20b1a2\")\nprivateKey := ed25519.PrivateKey(b)\n\nb, _ = hex.DecodeString(\"1eb9dbbbbc047c03fd70604e0071f0987e16b28b757225c11f00415d0e20b1a2\")\npublicKey := ed25519.PublicKey(b)\n\n// or create a new keypair \n// publicKey, privateKey, err := ed25519.GenerateKey(nil)\n\njsonToken := paseto.JSONToken{\n        Expiration: time.Now().Add(24 * time.Hour),\n        }\n        \n// Add custom claim    to the token    \njsonToken.Set(\"data\", \"this is a signed message\")\nfooter := \"some footer\"\n\n// Sign data\ntoken, err := paseto.Sign(privateKey, jsonToken, footer)\n// token = \"v2.public.eyJkYXRhIjoidGhpcyBpcyBhIHNpZ25lZCBtZXNzYWdlIiwiZXhwIjoiMjAxOC0wMy0xMlQxOTowODo1NCswMTowMCJ9Ojv0uXlUNXSFhR88KXb568LheLRdeGy2oILR3uyOM_-b7r7i_fX8aljFYUiF-MRr5IRHMBcWPtM0fmn9SOd6Aw.c29tZSBmb290ZXI\"\n\n// Verify data\nvar newJsonToken paseto.JSONToken\nvar newFooter string\nerr := paseto.Verify(token, publicKey, \u0026newJsonToken, \u0026newFooter)\n```\n\n## Use Parse() function to parse all supported token versions:\n**IMPORTANT**: Version 1 of the protocol is deprecated\n\n```go\nb, err := hex.DecodeString(\"2d2d2d2d2d424547494e205055424c4943204b45592d2d2d2d2d0d0a4d494942496a414e42676b71686b6947397730424151454641414f43415138414d49494243674b43415145417878636e47724e4f6136426c41523458707050640d0a746146576946386f7279746c4b534d6a66446831314c687956627a4335416967556b706a457274394d7649482f46384d444a72324f39486b36594b454b574b6f0d0a72333566364b6853303679357a714f722b7a4e34312b39626a52365633322b527345776d5a737a3038375258764e41334e687242633264593647736e57336c5a0d0a34356f5341564a755639553667335a334a574138355972362b6350776134793755632f56726f6d7a674679627355656e33476f724254626a783142384f514a440d0a73652f4b6b6855433655693358384264514f473974523455454775742f6c39703970732b3661474d4c57694357495a54615456784d4f75653133596b777038740d0a3148467635747a6872493055635948687638464a6b315a6435386759464158634e797975737834346e6a6152594b595948646e6b4f6a486e33416b534c4d306b0d0a6c774944415141420d0a2d2d2d2d2d454e44205055424c4943204b45592d2d2d2d2d\")\nblock, _ := pem.Decode(b)\nrsaPubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)\nv1PublicKey := rsaPubInterface.(*rsa.PublicKey)\n\nb, _ = hex.DecodeString(\"1eb9dbbbbc047c03fd70604e0071f0987e16b28b757225c11f00415d0e20b1a2\")\nv2PublicKey := ed25519.PublicKey(b)\n\n\nvar payload JSONToken\nvar footer string\nversion, err := paseto.Parse(token, \u0026payload, \u0026footer, symmetricKey, map[paseto.Version]crypto.PublicKey{paseto.V1: v1PublicKey, paseto.V2: v2PublicKey})\n```\n\nFor more information see *_test.go files.\n\n# Benchmarks\nMacBook Pro (15-inch, 2018)\nCPU: 2,6 GHz Intel Core i7\nRAM: 32 GB 2400 MHz DDR4\nOS: macOS 10.14.6\nGO: 1.13.7\n\n```\n$ go test -bench . -benchmem\n\nBenchmark_V2_JSONToken_Encrypt-12         137578              8532 ns/op            4186 B/op         59 allocs/op\nBenchmark_V2_JSONToken_Decrypt-12         139309              7970 ns/op            2048 B/op         63 allocs/op\nBenchmark_V2_JSONToken_Sign-12             21598             55817 ns/op            4426 B/op         60 allocs/op\nBenchmark_V2_JSONToken_Verify-12            8772            132142 ns/op            2528 B/op         64 allocs/op\nBenchmark_V2_String_Encrypt-12            544958              2051 ns/op            1176 B/op         23 allocs/op\nBenchmark_V2_String_Decrypt-12           1000000              1054 ns/op             568 B/op         18 allocs/op\nBenchmark_V2_String_Sign-12                25144             47645 ns/op            1144 B/op         23 allocs/op\nBenchmark_V2_String_Verify-12               9408            125524 ns/op             744 B/op         18 allocs/op\n```\n\n# Supported PASETO Versions\n## Version 2\nVersion 2 (the recommended version by the specification) is fully supported.\n\n## Version 1\nVersion 1 (the compatibility version) is fully supported.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fo1egl%2Fpaseto","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fo1egl%2Fpaseto","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fo1egl%2Fpaseto/lists"}