{"id":17974703,"url":"https://github.com/meeb/handshake","last_synced_at":"2025-04-03T23:43:19.044Z","repository":{"id":57436668,"uuid":"446320954","full_name":"meeb/handshake","owner":"meeb","description":"Authentication token generation and validation library.","archived":false,"fork":false,"pushed_at":"2022-01-11T07:39:26.000Z","size":16,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-03-09T19:35:44.001Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","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/meeb.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}},"created_at":"2022-01-10T07:26:31.000Z","updated_at":"2022-04-26T06:30:29.000Z","dependencies_parsed_at":"2022-09-09T23:23:10.416Z","dependency_job_id":null,"html_url":"https://github.com/meeb/handshake","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/meeb%2Fhandshake","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/meeb%2Fhandshake/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/meeb%2Fhandshake/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/meeb%2Fhandshake/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/meeb","download_url":"https://codeload.github.com/meeb/handshake/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247097974,"owners_count":20883127,"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-10-29T17:15:10.212Z","updated_at":"2025-04-03T23:43:19.015Z","avatar_url":"https://github.com/meeb.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# handshake\n\nA Python library to create and validate authentication tokens.\n\n`handshake` is used to generate and validate arbitrary authentication tokens\nthat contain arbitrary metadata and support expiration. It uses basic\ncryptographic primitives (hashing, HMACs) and is based around the concept of a\nshared private secret for security.\n\nExample usage would be to create namespaced authentication tokens for clients\nof an API which another service can check is valid and hasn't expired. The\ntokens are safe to be made public, put in headers etc. and can be used like\nsession tokens.\n\nThe tokens are strings in the format of:\n\n```\narbitrary:data:here:timestamp:random:signature\n```\n\nAll fields other than timestamp, random and signature are optional. Signatures\nare in the format of:\n\n```\nHMAC(arbitrary:data:here:timestamp:random){shared_secret}\n```\n\nThe library is designed to allow whatever metadata is required into the token,\nsuch as the first parameter could be a namespace and the second parameter an\nobject id. This allows tokens to be easily split between internal systems and\nuses while containing metadata or IDs for other objects.\n\nFor example, you could use `handshake` to allow an API to generate tokens which\na client stores for a variable amount of time and can verify their state with\nother services. The arbitrary data prefix can be used to store an application\nnamespace and the UUID of the object being referenced (such as `user:uuid` or\n`service:recordtype:uuid`). This library is of most use if you have multiple\ndiverse systems, microservices or other distributed endpoints that require\nad-hoc authentication and something like JWT or OAuth is overkill.\n\n\n## Installation\n\n`handshake` is pure Python and has no dependancies. You can install `handshake`\nvia pip:\n\n```bash\n$ pip install handshake\n```\n\nAny modern version of Python3 will be compatible.\n\n\n## Usage\n\n`handshake` has one class providing two basic public functions. Examples:\n\n```python\nimport os\nfrom handshake import AuthToken\n\n# The shared secret, keep this private, can be str or bytes but needs to be\n# from a cryptographically secure source\nsecret = os.urandom(128)\n\n# Create the instance\ntoken = AuthToken(secret)\n\n# Basic token with no additional parameters\nplain_token = token.create()\ntoken.verify(plain_token)\n\n# The token must be no more than 300 seconds old\nplain_token = token.create()\ntoken.verify(plain_token, time_range=300)\n\n# Namespaced but no specific item, namespace is arbitrary\nnamespaced_token = token.create('namespace')\ntoken.verify(namespaced_token)\n\n# Namespaced and with an arbitrary item ID\nfrom uuid import uuid4\nclient_token = token.create('user', uuid4())\ntoken.verify(client_token)\n\n# Lots of metadata\nclient_token = token.create('network', 'node', '12345', '67890')\ntoken.verify(client_token)\n\n# Use blake2s for hashes and signatures\nfrom hashlib import blake2s\ntoken = AuthToken(secret, hashfunc=blake2s)\nblake2s_token = token.create()\ntoken.verify(blake2s_token)\n```\n\nIf a token fails to validate it raise the relevent exception:\n\n```python\n# Create a token with one secret\ntoken = AuthToken('a fixed secret string')\nplain_token = token.create()\n\n# Attempt to verify it with a different token, this is invalid\ntoken_with_different_secret = AuthToken('not the same secret string')\ntoken_with_different_secret.verify(plain_token)\n# ... a child of handshake.errors.InvalidTokenError exception is raised\n```\n\n## Limitations\n\nThe secret must be at least 16 bytes or characters and no more than 1024 bytes\nor characters. The total generated token length cannot be longer than 2048\ncharacters.\n\n\n## Full API synopsis\n\n### `handshake.AuthToken(secret=str_or_bool, hashfunc=function)`\n\nInitiates an AuthToken object using the specified secret. The secret is\nrequired. It must be either a string or a bytes and must be between 32 and 1024\ncharacters or bytes in length. The secret should be sourced from a\ncryptographically safe random source, such as `os.urandom`.\n\n`hashfunc` defaults to `hashlib.sha256` but you can replace it with another\nhash function if you need to.\n\n### `handshake.AuthToken.create(*arbitrary str)`\n\nCreates an authentication token.\n\n### `handshake.AuthToken.verify(token=str, time_range=int)`\n\nVerifies an authentication token created with `handshake.AuthToken.create()`.\n\n`time_range` is an optional integer which if set specifies the valid time\nrange the token must have been generated within. This is used to verify\nexpiring tokens. It defaults to `0` which disables time range validation.\n\nIf the token is valid a tuple containing any arbitrary data in the token. For\nexample a token of\n\n```\narbitrary:data:here:timestamp:random:signature\n```\n\nIf valid would return a tuple of:\n\n```python\n('arbitrary', 'data', 'here')\n```\n\nIf the token is invalid for any reason a `handshake.errors.InvalidTokenError`\nexception is raised (or a child exception of\n`handshake.errors.InvalidTokenError`). You can handle different errors by\ncatching them specifically and the exception names describe the event:\n\n```python\nimport os\nfrom handshake import AuthToken, errors\n\nsecret = os.urandom(128)\ntoken = AuthToken(secret)\ntest_token = token.create()\n\ntry:\n    token.verify(test_token)\nexcept errors.TokenExpiredError as e:\n    print(e)\nexcept errors.TokenSignatureError as e:\n    print(e)\nexcept errors.InvalidTokenError as e:\n    print(e)\n```\n\n\n# Tests\n\nThere is a test suite that you can run by cloning this repository and\nexecuting:\n\n```bash\n$ make test\n```\n\n\n# Contributing\n\nAll properly formatted and sensible pull requests, issues and comments are\nwelcome.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmeeb%2Fhandshake","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmeeb%2Fhandshake","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmeeb%2Fhandshake/lists"}