{"id":15637967,"url":"https://github.com/linusu/secure-remote-password","last_synced_at":"2025-04-09T20:05:54.198Z","repository":{"id":48703653,"uuid":"102848648","full_name":"LinusU/secure-remote-password","owner":"LinusU","description":"A modern SRP implementation for Node.js and Web Browsers","archived":false,"fork":false,"pushed_at":"2022-10-26T11:47:51.000Z","size":93,"stargazers_count":103,"open_issues_count":16,"forks_count":25,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-04-09T20:05:50.424Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/LinusU.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-09-08T10:14:59.000Z","updated_at":"2025-01-15T20:07:50.000Z","dependencies_parsed_at":"2023-01-20T08:59:06.696Z","dependency_job_id":null,"html_url":"https://github.com/LinusU/secure-remote-password","commit_stats":null,"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LinusU%2Fsecure-remote-password","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LinusU%2Fsecure-remote-password/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LinusU%2Fsecure-remote-password/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LinusU%2Fsecure-remote-password/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/LinusU","download_url":"https://codeload.github.com/LinusU/secure-remote-password/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248103872,"owners_count":21048245,"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-03T11:16:33.528Z","updated_at":"2025-04-09T20:05:54.162Z","avatar_url":"https://github.com/LinusU.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Secure Remote Password for JavaScript\n\nA modern [SRP](http://srp.stanford.edu) implementation for Node.js and Web Browsers.\n\n## Installation\n\n```sh\nnpm install --save secure-remote-password\n```\n\n## Usage\n\n### Signing up\n\nWhen creating an account with the server, the client will provide a salt and a verifier for the server to store. They are calculated by the client as follows:\n\n```js\nconst srp = require('secure-remote-password/client')\n\n// These should come from the user signing up\nconst username = 'linus@folkdatorn.se'\nconst password = '$uper$ecure'\n\nconst salt = srp.generateSalt()\nconst privateKey = srp.derivePrivateKey(salt, username, password)\nconst verifier = srp.deriveVerifier(privateKey)\n\nconsole.log(salt)\n//=\u003e FB95867E...\n\nconsole.log(verifier)\n//=\u003e 9392093F...\n\n// Send `username`, `salt` and `verifier` to the server\n```\n\n*note:* `derivePrivateKey` is provided for completeness with the SRP 6a specification. It is however recommended to use some form of \"slow hashing\", like [PBKDF2](https://en.wikipedia.org/wiki/PBKDF2), to reduce the viability of a brute force attack against the verifier.\n\n### Logging in\n\nAuthenticating with the server involves mutliple steps.\n\n**1** - The client generates a secret/public ephemeral value pair.\n\n```js\nconst srp = require('secure-remote-password/client')\n\n// This should come from the user logging in\nconst username = 'linus@folkdatorn.se'\n\nconst clientEphemeral = srp.generateEphemeral()\n\nconsole.log(clientEphemeral.public)\n//=\u003e DE63C51E...\n\n// Send `username` and `clientEphemeral.public` to the server\n```\n\n**2** - The server receives the client's public ephemeral value and username. Using the username we retrieve the `salt` and `verifier` from our user database. We then generate our own ephemeral value pair.\n\n*note:* if no user can be found in the database, a bogus salt and ephemeral value should be returned, to avoid leaking which users have signed up\n\n```js\nconst srp = require('secure-remote-password/server')\n\n// This should come from the user database\nconst salt = 'FB95867E...'\nconst verifier = '9392093F...'\n\nconst serverEphemeral = srp.generateEphemeral(verifier)\n\nconsole.log(serverEphemeral.public)\n//=\u003e DA084F5C...\n\n// Store `serverEphemeral.secret` for later use\n// Send `salt` and `serverEphemeral.public` to the client\n```\n\n**3** - The client can now derive the shared strong session key, and a proof of it to provide to the server.\n\n```js\nconst srp = require('secure-remote-password/client')\n\n// This should come from the user logging in\nconst password = '$uper$ecret'\n\nconst privateKey = srp.derivePrivateKey(salt, username, password)\nconst clientSession = srp.deriveSession(clientEphemeral.secret, serverPublicEphemeral, salt, username, privateKey)\n\nconsole.log(clientSession.key)\n//=\u003e 2A6FF04E...\n\nconsole.log(clientSession.proof)\n//=\u003e 6F8F4AC3\n\n// Send `clientSession.proof` to the server\n```\n\n**4** - The server is also ready to derive the shared strong session key, and can verify that the client has the same key using the provided proof.\n\n```js\nconst srp = require('secure-remote-password/server')\n\n// Previously stored `serverEphemeral.secret`\nconst serverSecretEphemeral = '784D6E83...'\n\nconst serverSession = srp.deriveSession(serverSecretEphemeral, clientPublicEphemeral, salt, username, verifier, clientSessionProof)\n\nconsole.log(serverSession.key)\n//=\u003e 2A6FF04E...\n\nconsole.log(serverSession.proof)\n//=\u003e 92561B95\n\n// Send `serverSession.proof` to the client\n```\n\n**5** - Finally, the client can verify that the server have derived the correct strong session key, using the proof that the server sent back.\n\n```js\nconst srp = require('secure-remote-password/client')\n\nsrp.verifySession(clientEphemeral.public, clientSession, serverSessionProof)\n\n// All done!\n```\n\n## API\n\n### `Client`\n\n```js\nconst Client = require('secure-remote-password/client')\n```\n\n#### `Client.generateSalt() =\u003e string`\n\nGenerate a salt suitable for computing the verifier with.\n\n#### `Client.derivePrivateKey(salt, username, password) =\u003e string`\n\nDerives a private key suitable for computing the verifier with.\n\n#### `Client.deriveVerifier(privateKey) =\u003e string`\n\nDerive a verifier to be stored for subsequent authentication atempts.\n\n#### `Client.generateEphemeral() =\u003e { secret: string, public: string }`\n\nGenerate ephemeral values used to initiate an authentication session.\n\n#### `Client.deriveSession(clientSecretEphemeral, serverPublicEphemeral, salt, username, privateKey) =\u003e { key: string, proof: string }`\n\nComptue a session key and proof. The proof is to be sent to the server for verification.\n\n#### `Client.verifySession(clientPublicEphemeral, clientSession, serverSessionProof) =\u003e void`\n\nVerifies the server provided session proof. Throws an error if the session proof is invalid.\n\n### `Server`\n\n```js\nconst Server = require('secure-remote-password/server')\n```\n\n#### `generateEphemeral(verifier)`\n\nGenerate ephemeral values used to continue an authentication session.\n\n#### `deriveSession(serverSecretEphemeral, clientPublicEphemeral, salt, username, verifier, clientSessionProof)`\n\nComptue a session key and proof. The proof is to be sent to the client for verification.\n\nThrows an error if the session proof from the client is invalid.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flinusu%2Fsecure-remote-password","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flinusu%2Fsecure-remote-password","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flinusu%2Fsecure-remote-password/lists"}