{"id":18937465,"url":"https://github.com/rollerworks/split-token","last_synced_at":"2025-04-15T18:32:06.308Z","repository":{"id":50982740,"uuid":"165898620","full_name":"rollerworks/split-token","owner":"rollerworks","description":"Split Tokens: Token-Based Authentication Protocol without Side-Channels","archived":false,"fork":false,"pushed_at":"2024-01-06T13:02:16.000Z","size":64,"stargazers_count":4,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-29T01:03:33.673Z","etag":null,"topics":["authentication","crypto","php","rollerworks","security","sodium","split-token","token"],"latest_commit_sha":null,"homepage":null,"language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rollerworks.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","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":"2019-01-15T18:01:29.000Z","updated_at":"2023-11-06T10:00:18.000Z","dependencies_parsed_at":"2024-01-06T13:02:25.369Z","dependency_job_id":"ab656e3a-872f-47da-aab8-7969d50d82d4","html_url":"https://github.com/rollerworks/split-token","commit_stats":{"total_commits":10,"total_committers":2,"mean_commits":5.0,"dds":"0.19999999999999996","last_synced_commit":"0d25397a031b01a0c44ceda67e5c0248ecd951f7"},"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rollerworks%2Fsplit-token","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rollerworks%2Fsplit-token/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rollerworks%2Fsplit-token/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rollerworks%2Fsplit-token/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rollerworks","download_url":"https://codeload.github.com/rollerworks/split-token/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249129235,"owners_count":21217312,"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":["authentication","crypto","php","rollerworks","security","sodium","split-token","token"],"created_at":"2024-11-08T12:11:17.288Z","updated_at":"2025-04-15T18:32:01.294Z","avatar_url":"https://github.com/rollerworks.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"Rollerworks SplitToken Component\n================================\n\nSplitToken provides a Token-Based Authentication Protocol without Side-Channels.\n\nThis technique is based of [Split Tokens: Token-Based Authentication Protocols without Side-Channels].\nWhich was first proposed by Paragon Initiative Enterprises.\n\nSplitToken-Based Authentication is best used for password resetting or one-time\nsingle-logon.\n\nWhile possible, this technique is not recommended as a replacement for\nOAuth or Json Web Tokens.\n\n## Introduction\n\nUnlike _traditional_ Token-Based Authentication Protocols a SplitToken consists\nof two parts: The **selector** (used in the query) and the **verifier**\n(not used in the query).\n\n* The selector is a 24 bytes fixed-length random string, which used as an identifier.\n  You can safely create an unique index for field.\n\n* The verifier works as a password and is only provided to the user,\n  the database only holds a salted (cryptographic) hash of the verifier.\n\n  The length of this value is heavily dependent on the used hashing algorithm\n  and should not be hardcoded.\n\nThe full token is provided to the user or recipient and functions as a combined\nidentifier (selector) and password (verifier).\n\n**Caution: You NEVER store the full token as-is!** You only store the selector,\nand a (cryptographic) hash of the verifier.\n\n## Installation\n\nTo install this package, add `rollerworks/split-token` to your composer.json:\n\n```bash\n$ php composer.phar require rollerworks/split-token\n```\n\nNow, [Composer][composer] will automatically download all required files,\nand install them for you.\n\n## Requirements\n\nPHP 8.1 with the sodium extension enabled (default since PHP 8).\n\n## Basic Usage\n\n```php\n\u003c?php\nuse Rollerworks\\Component\\SplitToken\\Argon2SplitTokenFactory;\n\n// First, create the factory to generate a new SplitToken.\n//\n// Note: For unit testing it's highly recommended to use\n// the FakeSplitTokenFactory instead as cryptographic operations\n// can a little heavy.\n\n// Default configuration, shown here for clarity.\n$config = [\n    'memory_cost' =\u003e \\PASSWORD_ARGON2_DEFAULT_MEMORY_COST,\n    'time_cost' =\u003e \\PASSWORD_ARGON2_DEFAULT_TIME_COST,\n    'threads' =\u003e \\PASSWORD_ARGON2_DEFAULT_THREADS,\n];\n\n// Either a DateInterval or a DateInterval parsable-string\n$defaultLifeTime = null;\n\n$splitTokenFactory = new Argon2SplitTokenFactory(/*config: $config, */ $defaultLifeTime);\n\n// Optionally set PSR/Clock compatible instance\n// $splitTokenFactory-\u003esetClock();\n\n// Step 1. Create a new SplitToken for usage\n\n$token = $splitTokenFactory-\u003egenerate();\n\n// The $authToken holds a \\ParagonIE\\HiddenString\\HiddenString to prevent\n// leakage of this value. You need to cast this object to an actual string\n// at of usage.\n//\n// The $authToken is to be shared with the receiver (user) only.\n// The value is already encoded as base64 uri-safe string.\n//\n//\n// AGAIN, DO NOT STORE \"THIS\" VALUE IN THE DATABASE! Store the selector and verifier-hash instead.\n//\n$authToken = $token-\u003etoken(); // Returns a \\ParagonIE\\HiddenString\\HiddenString object\n\n// Indicate when the token must expire. Note that you need to clear the token from storage yourself.\n// Pass null (or leave this method call absent) to never expire the token (not recommended).\n//\n// If not provided uses \"now\" + $defaultLifeTime of the factory constructor.\n$authToken-\u003eexpireAt(new \\DateTimeImmutable('+1 hour'));\n\n// Now to store the token cast the SplitToken to a SplitTokenValueHolder object.\n//\n// Unlike SplitToken this class is final and doesn't hold the full-token string.\n//\n// Additionally you store the token with metadata (array only),\n// See the linked manual below for more information.\n$holder = $token-\u003etoValueHolder();\n\n// Setting the token would look something like this.\n\n// UPDATE site_user\n// SET\n//   recovery_selector = $holder-\u003eselector(),\n//   recovery_verifier = $holder-\u003everifierHash(),\n//   recovery_expires_at = $holder-\u003eexpiresAt(),\n//   recovery_metadata = json_encode($holder-\u003emetadata()),\n//   recovery_timestamp = NOW()\n// WHERE user_id = ...\n\n// ----\n\n// Step 2. Reconstruct the SplitToken from a user provided string.\n\n// When the user provides the token verify if it's valid.\n// This will throw an exception of token is not of the expected length.\n\n$token = $splitTokenFactory-\u003efromString($_GET['token']);\n\n// $result = SELECT user_id, recover_verifier, recovery_expires_at, recovery_metadata WHERE recover_selector = $token-\u003eselector()\n$holder = new SplitTokenValueHolder($token-\u003eselector(), $result['recovery_verifier'], $result['recovery_expires_at'], json_decode($result['recovery_metadata'], true));\n\nif ($token-\u003ematches($holder)) {\n    echo 'OK, you have access';\n} else {\n    // Note: Make sure to remove the token from storage.\n\n    echo 'NO, I cannot let you do this John.';\n}\n```\n\nOnce a result is found using the selector, the stored verifier-hash is used to\ncompute a matching hash of the provided verifier. And the values are compared\nin constant-time to protect against side-channel attacks.\n\n**See also:**\n\n* [Replacing an existing token](doc/replace-existing-token.md)\n* [Using metadata for advanced usage](doc/using-metadata.md)\n* [Configuring the hasher](doc/configuring-hasher.md)\n\n## Error Handling\n\nBecause of security reasons, a `SplitToken` only throws generic runtime\nexceptions for wrong usage, but no detailed exceptions about invalid input.\n\nIn the case of an error the memory allocation of the verifier and full token\nis zeroed to prevent leakage during a core dump or unhandled exception.\n\n## Versioning\n\nFor transparency and insight into the release cycle, and for striving\nto maintain backward compatibility, this package is maintained under\nthe Semantic Versioning guidelines as much as possible.\n\nReleases will be numbered with the following format:\n\n`\u003cmajor\u003e.\u003cminor\u003e.\u003cpatch\u003e`\n\nAnd constructed with the following guidelines:\n\n* Breaking backward compatibility bumps the major (and resets the minor and patch)\n* New additions without breaking backward compatibility bumps the minor (and resets the patch)\n* Bug fixes and misc changes bumps the patch\n\nFor more information on SemVer, please visit \u003chttp://semver.org/\u003e.\n\n## Who is behind this library?\n\nThis library is brought to you by [Sebastiaan Stok](https://github.com/sstok).\n\nThe Split Token idea was first proposed by Paragon Initiative Enterprises.\n\n## License\n\nThe Source Code of this package is subject to the terms of the\nMozilla Public License, version 2.0 ([MPLv2.0 License](LICENSE)).\n\nWhich can be safely used with any other license including MIT\nand GNU GPL.\n\n[Split Tokens: Token-Based Authentication Protocols without Side-Channels]: https://paragonie.com/blog/2017/02/split-tokens-token-based-authentication-protocols-without-side-channels\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frollerworks%2Fsplit-token","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frollerworks%2Fsplit-token","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frollerworks%2Fsplit-token/lists"}