{"_id":"@davidwells/cogneato","_rev":"6-832bb7a76d252831679644546baf23e3","name":"@davidwells/cogneato","dist-tags":{"latest":"0.6.0"},"versions":{"0.4.2":{"name":"@davidwells/cogneato","version":"0.4.2","keywords":["cognito","srp","aws","idp"],"author":{"name":"Paul Nilsson"},"license":"MIT","_id":"@davidwells/cogneato@0.4.2","maintainers":[{"name":"davidwells","email":"davidgregorywells@gmail.com"}],"homepage":"https://github.com/ravenscar/franken-srp#readme","bugs":{"url":"https://github.com/ravenscar/franken-srp/issues"},"dist":{"shasum":"a0688e2a6a2d89b4c7ef4f1b37642ccbf3316876","tarball":"https://registry.npmjs.org/@davidwells/cogneato/-/cogneato-0.4.2.tgz","fileCount":315,"integrity":"sha512-3e01jhhnmFS4O+DmZk6rboB6UgLCsBCjIEl0/uRyBW+rbcPRoAN99kXQgmwG74mONQvQMfVsmPo0AWJh0BzEyA==","signatures":[{"sig":"MEUCIQCfGo1UMDDY0ahaNP2jCnigG/Q+mkXdtArzi7JvebVnkAIgRW2gNOqECQy9o112QHSTkE1V7Lu3Ut1kdTgy3brjMvQ=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":248395,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJge13QCRA9TVsSAnZWagAAFVcP/0f3wrTBw26dkTZYQtAx\nCSVf0+jiGhxcicFcSNEHAriTzAzCZJK1svDXC8G91fkyU+VxYdCyyjs6e5/X\nI2yfVboUGPQbqQAF3G+GO4SJ7anzEr/h7sA3HYxET/izcd8Ysjh/xsDJFFBy\nh+E4b78G24gT4+1JNoKfNyRtjagljjWZv+vBi0zqCdKfOCYEprH3HG00WSKl\nHuXDGgmGuzsDyeQQrnGFo8brSL77VuUh2R67nA93volspxCnzK+2Y7fAdl6M\nuix+ewxUSbQ/8aFO7Qglo6NRdYI6FcehPmlL9IemLaYl9LxzedtMQwS505VS\ntGfNlryUepY3HgGTmtcqV1UrOqevkGr1vnDguNett2Jkxq0yejnC+tUJxr4d\nS44MaG9z+nYYRXvOTaqDeuyBzpIxLDCn+ixKY4WBss1PtnOBH0CzR91Kvq38\nNXKgnUWYSEyjk6ar6Q97/TW1BiZNfb47aEYzSLRyICLuJmKBfCZz89iEOG0c\nr/wsfC0VpNgoDblMMmY3Nxa9UAlMg9rUtO0RRK91roDGLjHQyo+ARiyL6pjV\nvz7ot45Wp2FcsrDG14D5/J75mNN+yXWV9yEz3VZsc/tTKUGhYCRuOXI1QNPY\nt6rXkmwEPWXhU0bNozmJqEOsj63VxR83GXcg+qnstuFhHs6DpVTgniBd9W8y\nKPWe\r\n=zQ2h\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","browser":"dist/index.js","gitHead":"3750ecf824e0c0f1cf558277fb5277ff01b4141f","scripts":{"test":"jest","build":"npm run clean && tsc --build --force","clean":"rm -rf tsconfig.tsbuildinfo dist","watch":"tsc --build --force --watch","cdktest":"jest src/test/cdk","cdkdeploy":"cd src/test/cdk && cdk deploy --outputs-file cfn_out.json","cdkdestroy":"cd src/test/cdk && cdk destroy","createTestUsers":"cd src/test && ts-node createTestUsers > test_users_out.json"},"_npmUser":{"name":"davidwells","email":"davidgregorywells@gmail.com"},"repository":{"url":"git+https://github.com/ravenscar/franken-srp.git","type":"git"},"_npmVersion":"6.10.0","description":"low level implementation lib for use with aws cognito srp login","directories":{},"_nodeVersion":"12.7.0","_hasShrinkwrap":false,"devDependencies":{"jest":"^26.6.3","uuid":"^8.3.2","aws-cdk":"^1.85.0","aws-sdk":"^2.831.0","ts-jest":"^26.4.4","ts-node":"^9.1.1","typescript":"^4.1.3","@types/jest":"^26.0.19","@types/node":"^14.14.14","@types/uuid":"^8.3.0","@aws-cdk/core":"^1.85.0","@aws-cdk/assert":"1.85.0","source-map-support":"^0.5.16","@aws-cdk/aws-cognito":"^1.85.0","minimal-cognito-totp":"^1.0.1"},"_npmOperationalInternal":{"tmp":"tmp/cogneato_0.4.2_1618697679822_0.7660678858154013","host":"s3://npm-registry-packages"}},"0.4.4":{"name":"@davidwells/cogneato","version":"0.4.4","keywords":["cognito","srp","aws","idp"],"author":{"name":"Paul Nilsson"},"license":"MIT","_id":"@davidwells/cogneato@0.4.4","maintainers":[{"name":"davidwells","email":"davidgregorywells@gmail.com"}],"homepage":"https://github.com/DavidWells/cogneato#readme","bugs":{"url":"https://github.com/DavidWells/cogneato/issues"},"dist":{"shasum":"eb2d461070c7156e6a37468379cdbdc85d50de66","tarball":"https://registry.npmjs.org/@davidwells/cogneato/-/cogneato-0.4.4.tgz","fileCount":316,"integrity":"sha512-XXD9nTiIh1CYZzEByfODwB8F8ADjXmN6bCOGJN3ieseD7QENnrEw4v4XP24ZfGFDWv9n1ulM1CZP4lbhhY1Vjw==","signatures":[{"sig":"MEUCIQCt/aIQ1840534SduOvwf2b4v3eNaTvj83Y5R5reER5TwIgYh5irb6Xqy3m7tsV4ODdiQFOsSx55zvLF5RlJ7w0uFE=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":318261},"main":"dist/index.js","types":"dist/index.d.ts","browser":"dist/index.js","gitHead":"f44aa932fe52fb5e1c555ec1a5e5d3c2ace61bb9","scripts":{"test":"jest","build":"npm run clean && tsc --build --force","clean":"rm -rf tsconfig.tsbuildinfo dist","watch":"tsc --build --force --watch","cdktest":"jest src/test/cdk","prepare":"npm run build","publish":"git push origin && git push origin --tags","cdkdeploy":"cd src/test/cdk && cdk deploy --outputs-file cfn_out.json","cdkdestroy":"cd src/test/cdk && cdk destroy","release:major":"npm version major && npm publish","release:minor":"npm version minor && npm publish","release:patch":"npm version patch && npm publish","createTestUsers":"cd src/test && ts-node createTestUsers > test_users_out.json"},"_npmUser":{"name":"davidwells","email":"davidgregorywells@gmail.com"},"repository":{"url":"git+https://github.com/DavidWells/cogneato.git","type":"git"},"_npmVersion":"10.9.4","description":"low level implementation lib for use with aws cognito srp login","directories":{},"_nodeVersion":"22.22.1","_hasShrinkwrap":false,"devDependencies":{"jest":"^26.6.3","uuid":"^8.3.2","aws-cdk":"^1.85.0","aws-sdk":"^2.831.0","ts-jest":"^26.4.4","ts-node":"^9.1.1","typescript":"^4.1.3","@types/jest":"^26.0.19","@types/node":"^14.14.14","@types/uuid":"^8.3.0","@aws-cdk/core":"^1.85.0","@aws-cdk/assert":"1.85.0","source-map-support":"^0.5.16","@aws-cdk/aws-cognito":"^1.85.0","minimal-cognito-totp":"^1.0.1"},"_npmOperationalInternal":{"tmp":"tmp/cogneato_0.4.4_1779512138618_0.6978236763964898","host":"s3://npm-registry-packages-npm-production"}},"0.5.1":{"name":"@davidwells/cogneato","version":"0.5.1","keywords":["cognito","srp","aws","idp"],"author":{"name":"Paul Nilsson"},"license":"MIT","_id":"@davidwells/cogneato@0.5.1","maintainers":[{"name":"davidwells","email":"davidgregorywells@gmail.com"}],"homepage":"https://github.com/DavidWells/cogneato#readme","bugs":{"url":"https://github.com/DavidWells/cogneato/issues"},"dist":{"shasum":"baf9081d18875ce8d224725e770c428220de0a18","tarball":"https://registry.npmjs.org/@davidwells/cogneato/-/cogneato-0.5.1.tgz","fileCount":326,"integrity":"sha512-B/gOyzs0HLsdMxpVG3fB5/h9bBDYlvuw7H47rehE+PHhF0fGcuOEUpnxzqukM4rO354MjvNMp2IugA6tzskZPQ==","signatures":[{"sig":"MEUCIFB3xVmafaDPkMRtr3vWB537BQZVlHrETBefcZ8m6drZAiEA9++rZE0gb+pisYA5NbttgxUhOJNtOnUsnJ8yZv8Rrm0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":327482},"main":"dist/index.js","types":"dist/index.d.ts","browser":"dist/index.js","gitHead":"820bbe96f42b7a19a835bc6a3350d1c9e7a9d7d9","scripts":{"test":"jest","build":"npm run clean && tsc --build --force","clean":"rm -rf tsconfig.tsbuildinfo dist","watch":"tsc --build --force --watch","cdktest":"jest src/test/cdk","prepare":"npm run build","publish":"git push origin && git push origin --tags","cdkdeploy":"cd src/test/cdk && cdk deploy --outputs-file cfn_out.json","cdkdestroy":"cd src/test/cdk && cdk destroy","release:major":"npm version major && npm publish","release:minor":"npm version minor && npm publish","release:patch":"npm version patch && npm publish","createTestUsers":"cd src/test && ts-node createTestUsers > test_users_out.json"},"_npmUser":{"name":"davidwells","email":"davidgregorywells@gmail.com"},"repository":{"url":"git+https://github.com/DavidWells/cogneato.git","type":"git"},"_npmVersion":"10.9.4","description":"low level implementation lib for use with aws cognito srp login","directories":{},"_nodeVersion":"22.22.1","_hasShrinkwrap":false,"devDependencies":{"jest":"^26.6.3","uuid":"^8.3.2","aws-cdk":"^1.85.0","aws-sdk":"^2.831.0","ts-jest":"^26.4.4","ts-node":"^9.1.1","typescript":"^4.1.3","@types/jest":"^26.0.19","@types/node":"^14.14.14","@types/uuid":"^8.3.0","@aws-cdk/core":"^1.85.0","@aws-cdk/assert":"1.85.0","source-map-support":"^0.5.16","@aws-cdk/aws-cognito":"^1.85.0","minimal-cognito-totp":"^1.0.1"},"_npmOperationalInternal":{"tmp":"tmp/cogneato_0.5.1_1779660104348_0.36702803218333435","host":"s3://npm-registry-packages-npm-production"}},"0.5.3":{"name":"@davidwells/cogneato","version":"0.5.3","keywords":["cognito","srp","aws","idp"],"author":{"name":"Paul Nilsson"},"license":"MIT","_id":"@davidwells/cogneato@0.5.3","maintainers":[{"name":"davidwells","email":"davidgregorywells@gmail.com"}],"homepage":"https://github.com/DavidWells/cogneato#readme","bugs":{"url":"https://github.com/DavidWells/cogneato/issues"},"dist":{"shasum":"a22f1dbef27122ab9f8455179524e5fe84165328","tarball":"https://registry.npmjs.org/@davidwells/cogneato/-/cogneato-0.5.3.tgz","fileCount":326,"integrity":"sha512-A37yr28Stj7P4XnlTRPWt1iD+yZu5AhPjJoZcVmesWu+tzlGtV3xvNIJx1ps0vZFkeC9sSmLM45eeulgCl5amQ==","signatures":[{"sig":"MEUCIDZ2b5EMh3B+CGd3lgLotW+Xggr61/D3Ff84uAoBKmTVAiEA38hLvp7KPstMex9r43/Qn3tnd8CeFff3VcP0rlL6WFs=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":327936},"main":"dist/index.js","types":"dist/index.d.ts","browser":"dist/index.js","gitHead":"3030d732ed3b0b73667aa7137d7a1d9af8d6edb3","scripts":{"test":"jest","build":"npm run clean && tsc --build --force","clean":"rm -rf tsconfig.tsbuildinfo dist","watch":"tsc --build --force --watch","cdktest":"jest src/test/cdk","prepare":"npm run build","publish":"git push origin && git push origin --tags","cdkdeploy":"cd src/test/cdk && cdk deploy --outputs-file cfn_out.json","cdkdestroy":"cd src/test/cdk && cdk destroy","release:major":"npm version major && npm publish","release:minor":"npm version minor && npm publish","release:patch":"npm version patch && npm publish","createTestUsers":"cd src/test && ts-node createTestUsers > test_users_out.json"},"_npmUser":{"name":"davidwells","email":"davidgregorywells@gmail.com"},"repository":{"url":"git+https://github.com/DavidWells/cogneato.git","type":"git"},"_npmVersion":"10.9.4","description":"low level implementation lib for use with aws cognito srp login","directories":{},"_nodeVersion":"22.22.1","_hasShrinkwrap":false,"devDependencies":{"jest":"^26.6.3","uuid":"^8.3.2","aws-cdk":"^1.85.0","aws-sdk":"^2.831.0","ts-jest":"^26.4.4","ts-node":"^9.1.1","typescript":"^4.1.3","@types/jest":"^26.0.19","@types/node":"^14.14.14","@types/uuid":"^8.3.0","@aws-cdk/core":"^1.85.0","@aws-cdk/assert":"1.85.0","source-map-support":"^0.5.16","@aws-cdk/aws-cognito":"^1.85.0","minimal-cognito-totp":"^1.0.1"},"_npmOperationalInternal":{"tmp":"tmp/cogneato_0.5.3_1779665753319_0.9357560232198006","host":"s3://npm-registry-packages-npm-production"}},"0.6.0":{"name":"@davidwells/cogneato","version":"0.6.0","description":"low level implementation lib for use with aws cognito srp login","browser":"dist/index.js","main":"dist/index.js","types":"dist/index.d.ts","scripts":{"clean":"rm -rf tsconfig.tsbuildinfo dist","build":"npm run clean && tsc --build --force","prepare":"npm run build","watch":"tsc --build --force --watch","test":"jest","cdktest":"jest src/test/cdk","cdkdeploy":"cd src/test/cdk && cdk deploy --outputs-file cfn_out.json","cdkdestroy":"cd src/test/cdk && cdk destroy","createTestUsers":"cd src/test && ts-node createTestUsers > test_users_out.json","publish":"git push origin && git push origin --tags","release:patch":"npm version patch && npm publish","release:minor":"npm version minor && npm publish","release:major":"npm version major && npm publish"},"repository":{"type":"git","url":"git+https://github.com/DavidWells/saaslayer.git","directory":"packages/cogneato"},"keywords":["cognito","srp","aws","idp"],"author":{"name":"Paul Nilsson"},"license":"MIT","bugs":{"url":"https://github.com/DavidWells/saaslayer/issues"},"homepage":"https://github.com/DavidWells/saaslayer/tree/master/packages/cogneato#readme","devDependencies":{"@aws-cdk/assert":"1.85.0","@aws-cdk/aws-cognito":"^1.85.0","@aws-cdk/core":"^1.85.0","@types/jest":"^26.0.19","@types/node":"^14.14.14","@types/uuid":"^8.3.0","aws-cdk":"^1.85.0","aws-sdk":"^2.831.0","jest":"^26.6.3","minimal-cognito-totp":"^1.0.1","source-map-support":"^0.5.16","ts-jest":"^26.4.4","ts-node":"^9.1.1","typescript":"^4.1.3","uuid":"^8.3.2"},"gitHead":"bbc005f8ec4206654822e816db182daae57352ca","_id":"@davidwells/cogneato@0.6.0","_nodeVersion":"22.22.1","_npmVersion":"11.17.0","dist":{"integrity":"sha512-y4ICTcdTelMQnrrjQat8MVYG6NVWT5fplaAdu3sBtczKiTUwM2aWkCHKEYw8lrruZSAnHLPvjwidnh+wxVODHA==","shasum":"f4f221614275cef3951653c73ab0f0728cb1eb9f","tarball":"https://registry.npmjs.org/@davidwells/cogneato/-/cogneato-0.6.0.tgz","fileCount":393,"unpackedSize":351447,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCiM52J7SsEYdYYhSaeKWqznN9l7buTGM4a20d1zqtR8wIhAImenH0gCDeK233tJnwZaYjRpFckgUcUolIZY2K7IZTV"}]},"_npmUser":{"name":"davidwells","email":"davidgregorywells@gmail.com"},"directories":{},"maintainers":[{"name":"davidwells","email":"davidgregorywells@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/cogneato_0.6.0_1787068836958_0.7757344161936184"},"_hasShrinkwrap":false}},"time":{"created":"2021-04-17T22:14:39.782Z","modified":"2026-08-18T16:00:37.293Z","0.4.2":"2021-04-17T22:14:39.999Z","0.4.4":"2026-05-23T04:55:38.757Z","0.5.1":"2026-05-24T22:01:44.512Z","0.5.3":"2026-05-24T23:35:53.463Z","0.6.0":"2026-08-18T16:00:37.108Z"},"bugs":{"url":"https://github.com/DavidWells/saaslayer/issues"},"author":{"name":"Paul Nilsson"},"license":"MIT","homepage":"https://github.com/DavidWells/saaslayer/tree/master/packages/cogneato#readme","keywords":["cognito","srp","aws","idp"],"repository":{"type":"git","url":"git+https://github.com/DavidWells/saaslayer.git","directory":"packages/cogneato"},"description":"low level implementation lib for use with aws cognito srp login","maintainers":[{"name":"davidwells","email":"davidgregorywells@gmail.com"}],"readme":"# @davidwells/cogneato\n\n<div align=\"center\">\n\n[![npm version](https://img.shields.io/npm/v/@davidwells/cogneato.svg)](https://www.npmjs.com/package/@davidwells/cogneato)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)\n[![TypeScript](https://img.shields.io/badge/TypeScript-strict-blue.svg)](./tsconfig.json)\n\n</div>\n\nLow-level TypeScript helpers for AWS Cognito SRP login, refresh tokens, remembered devices, MFA challenges, sign-up, account operations, and identity-pool credential exchange.\n\n```bash\nnpm install @davidwells/cogneato\n```\n\n## TL;DR\n\n**The Problem**: Cognito's SRP auth flow is secure, but wiring it by hand means implementing SRP math, `InitiateAuth`, challenge responses, MFA loops, device confirmation, refresh tokens, and user account operations against low-level AWS JSON APIs.\n\n**The Solution**: Cogneato wraps those Cognito calls in small TypeScript functions while keeping the flow explicit. `srpLogin()` is an async generator, so your UI or service decides how to handle `NEW_PASSWORD_REQUIRED`, `SOFTWARE_MFA_REQUIRED`, `SMS_MFA_REQUIRED`, successful tokens, and errors.\n\n### Why Use Cogneato?\n\n| Feature | What It Does |\n|---------|--------------|\n| SRP login generator | Starts `USER_SRP_AUTH`, responds to password verifier challenges, yields MFA/new-password steps, and returns tokens. |\n| Remembered devices | Confirms new devices, stores reusable device credentials, and can reuse known devices on later logins. |\n| MFA helpers | Supports software-token MFA, SMS MFA, software-token association, token verification, and user MFA preference updates. |\n| User operations | Wraps sign-up, confirmation, password reset, password change, attribute verification, sign-out, and token revocation. |\n| Identity pools | Calls Cognito Identity `GetId` and `GetCredentialsForIdentity` for identity-pool credentials. |\n| Runtime-light design | Uses direct Cognito JSON requests instead of requiring the full AWS SDK at runtime. |\n\n## Quick Example\n\n```ts\nimport { srpLogin, refresh, changePassword } from \"@davidwells/cogneato\";\n\nconst login = srpLogin({\n  region: \"us-west-2\",\n  userPoolId: \"us-west-2_abc123\",\n  clientId: \"4exampleclientid\",\n  username: \"user@example.com\",\n  password: \"CorrectHorseBatteryStaple1!\",\n  device: undefined,\n  autoConfirmDevice: true,\n  autoRememberDevice: \"remembered\",\n});\n\nlet step = await login.next();\n\nif (step.value.code === \"SOFTWARE_MFA_REQUIRED\") {\n  step = await login.next(\"123456\");\n}\n\nif (step.value.code === \"NEW_PASSWORD_REQUIRED\") {\n  step = await login.next(\"NewPassword1!\");\n}\n\nif (step.value.code === \"ERROR\") {\n  throw step.value.error;\n}\n\nconst auth = step.value.response!;\n\nawait refresh({\n  region: \"us-west-2\",\n  clientId: \"4exampleclientid\",\n  refreshToken: auth.tokens.refreshToken,\n  deviceKey: auth.newDevice?.key,\n});\n\nawait changePassword({\n  region: \"us-west-2\",\n  accessToken: auth.tokens.accessToken,\n  previousPassword: \"CorrectHorseBatteryStaple1!\",\n  proposedPassword: \"NewPassword1!\",\n});\n```\n\n## Design Philosophy\n\n### Keep Cognito Explicit\n\nCogneato does not hide Cognito behind a large session manager. It exposes the flow as functions and return values you can store, inspect, and test:\n\n```ts\nconst step = await login.next();\n\nswitch (step.value.code) {\n  case \"SOFTWARE_MFA_REQUIRED\":\n  case \"SMS_MFA_REQUIRED\":\n  case \"NEW_PASSWORD_REQUIRED\":\n  case \"TOKENS\":\n  case \"ERROR\":\n    break;\n}\n```\n\n### Make Interactive Auth Natural\n\nSRP login is not always a single request. Users may need to enter a new password, a TOTP code, or an SMS code. The async generator shape lets the caller provide those values when Cognito asks for them.\n\n### Store Only What You Need\n\nWhen Cognito returns `NewDeviceMetadata`, Cogneato can confirm the device and return the reusable device key, group key, and generated device password:\n\n```ts\nconst device = auth.newDevice && {\n  key: auth.newDevice.key,\n  groupKey: auth.newDevice.groupKey,\n  password: auth.newDevice.password!,\n};\n```\n\n### Use Small Operation Wrappers\n\nAccount operations map closely to Cognito API names, so tests and callers can reason about the exact request being made:\n\n```ts\nawait updateUserAttributes({\n  region,\n  accessToken,\n  userAttributes: [{ Name: \"custom:tenantId\", Value: \"tenant-123\" }],\n});\n```\n\n## How Cogneato Compares\n\n| Capability | Cogneato | AWS Amplify Auth | AWS SDK CognitoIdentityProvider | Hand-rolled Cognito calls |\n|------------|----------|------------------|----------------------------------|---------------------------|\n| SRP math included | Yes | Yes | No | You write it |\n| Async challenge flow | Explicit generator | Managed internally | Manual | Manual |\n| Remembered device support | Built in | Framework-managed | Manual | Manual |\n| Direct Cognito operations | Yes | Partly abstracted | Yes | Yes |\n| Runtime size/control | Small focused package | Larger framework | Larger SDK client | Depends on your code |\n| Hosted UI/OAuth abstraction | No | Yes | No | No |\n| Best fit | Custom auth flows needing precise control | App teams using Amplify conventions | Backend services already using AWS SDK | Specialized experiments |\n\n**Use Cogneato when:**\n\n- You need Cognito SRP without adopting Amplify.\n- You want to own UI state for MFA, forced password changes, and device prompts.\n- You want small wrappers around Cognito user-pool and identity-pool operations.\n\n**Cogneato may not be ideal when:**\n\n- You want Cognito Hosted UI, OAuth redirects, or social-provider flows.\n- Your app already standardizes on Amplify Auth.\n- You need admin-only Cognito APIs such as `AdminCreateUser` or `AdminInitiateAuth`.\n\n## Installation\n\n### npm\n\n```bash\nnpm install @davidwells/cogneato\n```\n\n### pnpm\n\n```bash\npnpm add @davidwells/cogneato\n```\n\n### yarn\n\n```bash\nyarn add @davidwells/cogneato\n```\n\n### From Source\n\n```bash\ngit clone https://github.com/DavidWells/saaslayer.git\ncd saaslayer/packages/cogneato\nnpm install\nnpm run build\n```\n\nThe package publishes CommonJS output and TypeScript declarations from `dist/`.\n\n## Quick Start\n\n### 1. Configure your app client\n\nUse a Cognito user-pool app client that supports `USER_SRP_AUTH`. Collect these values from your infrastructure outputs:\n\n```ts\nconst cognito = {\n  region: \"us-west-2\",\n  userPoolId: \"us-west-2_abc123\",\n  clientId: \"4exampleclientid\",\n};\n```\n\n### 2. Run SRP login\n\n```ts\nimport { srpLogin } from \"@davidwells/cogneato\";\n\nconst login = srpLogin({\n  ...cognito,\n  username: \"user@example.com\",\n  password: \"CorrectHorseBatteryStaple1!\",\n  device: undefined,\n  autoConfirmDevice: true,\n  autoRememberDevice: \"remembered\",\n  clientMetadata: { source: \"web\" },\n});\n```\n\n### 3. Handle challenge steps\n\n```ts\nlet result = await login.next();\n\nwhile (!result.done) {\n  if (result.value.code === \"SOFTWARE_MFA_REQUIRED\") {\n    result = await login.next(await promptForTotpCode());\n    continue;\n  }\n\n  if (result.value.code === \"SMS_MFA_REQUIRED\") {\n    console.log(`Code sent to ${result.value.hint}`);\n    result = await login.next(await promptForSmsCode());\n    continue;\n  }\n\n  if (result.value.code === \"NEW_PASSWORD_REQUIRED\") {\n    result = await login.next(await promptForNewPassword());\n    continue;\n  }\n\n  throw result.value.error;\n}\n\nif (result.value.code === \"ERROR\") {\n  throw result.value.error;\n}\n\nconst auth = result.value.response!;\n```\n\n### 4. Persist remembered-device metadata\n\n```ts\nif (auth.newDevice?.password) {\n  await saveDeviceForUser(auth.username, {\n    key: auth.newDevice.key,\n    groupKey: auth.newDevice.groupKey,\n    password: auth.newDevice.password,\n  });\n}\n```\n\n### 5. Reuse the device on the next login\n\n```ts\nconst savedDevice = await loadDeviceForUser(\"user@example.com\");\n\nconst login = srpLogin({\n  ...cognito,\n  username: \"user@example.com\",\n  password: \"CorrectHorseBatteryStaple1!\",\n  device: savedDevice,\n  autoConfirmDevice: true,\n  autoRememberDevice: \"remembered\",\n});\n```\n\n## API Reference\n\n### `srpLogin(params)`\n\nRuns Cognito `USER_SRP_AUTH` as an async generator.\n\n```ts\nconst login = srpLogin({\n  region: \"us-west-2\",\n  userPoolId: \"us-west-2_abc123\",\n  clientId: \"4exampleclientid\",\n  username: \"user@example.com\",\n  password: \"CorrectHorseBatteryStaple1!\",\n  device: undefined,\n  autoConfirmDevice: true,\n  autoRememberDevice: \"remembered\",\n  clientMetadata: { source: \"web\" },\n  debugTracing: false,\n});\n```\n\nGenerator step codes:\n\n| Code | Meaning | Caller Response |\n|------|---------|-----------------|\n| `TOKENS` | Login completed. | Read `step.value.response`. |\n| `SOFTWARE_MFA_REQUIRED` | Cognito requires a six-digit TOTP code. | Call `login.next(\"123456\")`. |\n| `SMS_MFA_REQUIRED` | Cognito requires a six-digit SMS code. | Call `login.next(\"123456\")`. |\n| `NEW_PASSWORD_REQUIRED` | Cognito requires a password reset during login. | Call `login.next(\"NewPassword1!\")`. |\n| `ERROR` | Login failed. | Read or throw `step.value.error`. |\n\nSuccessful response shape:\n\n```ts\ntype TAuthResponse = {\n  username: string;\n  tokens: {\n    accessToken: string;\n    refreshToken: string;\n    idToken: string;\n    tokenType: string;\n    expiresIn: number;\n  };\n  newDevice?: {\n    key: string;\n    groupKey: string;\n    password?: string;\n    deviceAutoConfirmed: boolean;\n    deviceAutoRemembered?: \"remembered\" | \"not_remembered\";\n    userConfirmationNecessary?: boolean;\n  };\n};\n```\n\n### `refresh(params)`\n\nRefreshes access and ID tokens with a refresh token.\n\n```ts\nimport { refresh } from \"@davidwells/cogneato\";\n\nconst tokens = await refresh({\n  region: \"us-west-2\",\n  clientId: \"4exampleclientid\",\n  refreshToken: \"refresh-token\",\n  deviceKey: \"device-key\",\n});\n```\n\n### Sign-Up and Confirmation\n\n```ts\nimport {\n  signUp,\n  confirmSignUp,\n  resendConfirmationCode,\n} from \"@davidwells/cogneato\";\n\nawait signUp({\n  region,\n  clientId,\n  username: \"user@example.com\",\n  password: \"S3cret!pass\",\n  userAttributes: [\n    { Name: \"email\", Value: \"user@example.com\" },\n    { Name: \"custom:orgId\", Value: \"org-123\" },\n  ],\n  clientMetadata: { source: \"web\" },\n});\n\nawait confirmSignUp({\n  region,\n  clientId,\n  username: \"user@example.com\",\n  confirmationCode: \"123456\",\n});\n\nawait resendConfirmationCode({\n  region,\n  clientId,\n  username: \"user@example.com\",\n});\n```\n\n### Password Reset and Password Change\n\n```ts\nimport {\n  forgotPassword,\n  confirmForgotPassword,\n  changePassword,\n} from \"@davidwells/cogneato\";\n\nawait forgotPassword({\n  region,\n  clientId,\n  username: \"user@example.com\",\n});\n\nawait confirmForgotPassword({\n  region,\n  clientId,\n  username: \"user@example.com\",\n  confirmationCode: \"123456\",\n  password: \"NewPassword1!\",\n});\n\nawait changePassword({\n  region,\n  accessToken,\n  previousPassword: \"OldPassword1!\",\n  proposedPassword: \"NewPassword1!\",\n});\n```\n\n### User Profile and Account Operations\n\n```ts\nimport {\n  getUser,\n  updateUserAttributes,\n  getUserAttributeVerificationCode,\n  verifyUserAttribute,\n  globalSignOut,\n  revokeToken,\n} from \"@davidwells/cogneato\";\n\nconst user = await getUser({ region, accessToken });\n\nawait updateUserAttributes({\n  region,\n  accessToken,\n  userAttributes: [{ Name: \"email\", Value: \"new@example.com\" }],\n  clientMetadata: { source: \"settings\" },\n});\n\nawait getUserAttributeVerificationCode({\n  region,\n  accessToken,\n  attributeName: \"email\",\n});\n\nawait verifyUserAttribute({\n  region,\n  accessToken,\n  attributeName: \"email\",\n  code: \"123456\",\n});\n\nawait globalSignOut({ region, accessToken });\n\nawait revokeToken({\n  region,\n  clientId,\n  token: refreshToken,\n  clientSecret: \"optional-client-secret\",\n});\n```\n\n### Software Token MFA\n\n```ts\nimport {\n  associateSoftwareToken,\n  verifySoftwareToken,\n  setUserMfaPreference,\n} from \"@davidwells/cogneato\";\n\nconst association = await associateSoftwareToken({\n  region,\n  accessToken,\n});\n\nawait verifySoftwareToken({\n  region,\n  accessToken,\n  userCode: \"123456\",\n  friendlyDeviceName: \"Work phone\",\n});\n\nawait setUserMfaPreference({\n  region,\n  accessToken,\n  softwareTokenMfaSettings: { Enabled: true, PreferredMfa: true },\n  smsMfaSettings: { Enabled: false, PreferredMfa: false },\n  emailMfaSettings: { Enabled: false, PreferredMfa: false },\n  webAuthnMfaSettings: { Enabled: false },\n});\n```\n\n`associateSoftwareToken()` and `verifySoftwareToken()` also accept a challenge `session` instead of an `accessToken` when Cognito returns one during auth setup.\n\n### Identity Pool Credentials\n\n```ts\nimport {\n  getIdentityId,\n  getCredentialsForIdentity,\n} from \"@davidwells/cogneato\";\n\nconst { IdentityId } = await getIdentityId({\n  region,\n  identityPoolId: \"us-west-2:identity-pool-id\",\n  logins: {\n    \"cognito-idp.us-west-2.amazonaws.com/us-west-2_abc123\": idToken,\n  },\n});\n\nconst credentials = await getCredentialsForIdentity({\n  region,\n  identityId: IdentityId,\n  logins: {\n    \"cognito-idp.us-west-2.amazonaws.com/us-west-2_abc123\": idToken,\n  },\n});\n```\n\n### Low-Level Cognito Operations\n\nCogneato also exports lower-level auth operation helpers used by `srpLogin()`:\n\n| Export | Cognito Operation |\n|--------|-------------------|\n| `initiateUserSRPAuth` | `InitiateAuth` with `USER_SRP_AUTH` |\n| `respondPasswordVerifier` | `RespondToAuthChallenge` with `PASSWORD_VERIFIER` |\n| `respondSoftwareTokenMfa` | `RespondToAuthChallenge` with `SOFTWARE_TOKEN_MFA` |\n| `respondSmsMfa` | `RespondToAuthChallenge` with `SMS_MFA` |\n| `respondNewPasswordRequired` | `RespondToAuthChallenge` with `NEW_PASSWORD_REQUIRED` |\n| `respondDeviceSRPAuth` | `RespondToAuthChallenge` with `DEVICE_SRP_AUTH` |\n| `confirmDevice` | `ConfirmDevice` plus optional device remembered status |\n\nPrefer `srpLogin()` unless you need to assemble a custom Cognito challenge flow.\n\n## Configuration\n\nCogneato does not require a config file. Most apps keep Cognito deployment outputs in environment variables or generated service config.\n\n```ts\nexport const authConfig = {\n  region: process.env.COGNITO_REGION!,\n  userPoolId: process.env.COGNITO_USER_POOL_ID!,\n  clientId: process.env.COGNITO_CLIENT_ID!,\n  identityPoolId: process.env.COGNITO_IDENTITY_POOL_ID,\n};\n```\n\nExample `.env` values:\n\n```bash\nCOGNITO_REGION=us-west-2\nCOGNITO_USER_POOL_ID=us-west-2_abc123\nCOGNITO_CLIENT_ID=4exampleclientid\nCOGNITO_IDENTITY_POOL_ID=us-west-2:00000000-0000-0000-0000-000000000000\n```\n\nFor SaaSLayer services, prefer generated deployer outputs or module manifests over hard-coded stack assumptions.\n\n## Architecture\n\n```text\nApplication UI / Service\n        |\n        | imports @davidwells/cogneato\n        v\n+-----------------------------+\n| High-Level Auth Helpers     |\n| - srpLogin generator        |\n| - refresh                   |\n| - account operations        |\n| - MFA setup helpers         |\n+-----------------------------+\n        |\n        v\n+-----------------------------+\n| Cognito Operation Wrappers  |\n| - InitiateAuth              |\n| - RespondToAuthChallenge    |\n| - ConfirmDevice             |\n| - SignUp / ConfirmSignUp    |\n| - GetId / Credentials       |\n+-----------------------------+\n        |\n        v\n+-----------------------------+\n| SRP and Platform Layer      |\n| - SRP math                  |\n| - device verifier           |\n| - fetch / crypto wrappers   |\n| - Cognito JSON request      |\n+-----------------------------+\n        |\n        v\nAWS Cognito User Pools and Identity Pools\n```\n\n## Troubleshooting\n\n### `Incorrect username or password.`\n\nCognito returns this for bad credentials and, depending on app-client settings, may also return it when the user does not exist.\n\n```ts\nconst result = await login.next();\n\nif (result.value.code === \"ERROR\") {\n  console.error(result.value.error?.message);\n}\n```\n\n### `Expected 6 digit MFA code`\n\n`srpLogin()` validates MFA input before sending it to Cognito. Pass a string containing exactly six digits.\n\n```ts\nawait login.next(\"123456\");\n```\n\n### `NEW_PASSWORD_REQUIRED` never completes\n\nThe generator expects the next value to be the new password string.\n\n```ts\nlet step = await login.next();\n\nif (step.value.code === \"NEW_PASSWORD_REQUIRED\") {\n  step = await login.next(\"NewPassword1!\");\n}\n```\n\n### Device reuse fails with `Missing deviceParams`\n\nIf you pass a remembered device, include all three persisted fields.\n\n```ts\nconst device = {\n  key: saved.key,\n  groupKey: saved.groupKey,\n  password: saved.password,\n};\n```\n\n### `refresh()` succeeds but does not return a refresh token\n\nCognito refresh-token auth usually returns a new access token and ID token, not a new refresh token. Keep the original refresh token until your app signs out or revokes it.\n\n### Browser build cannot find Node globals\n\nThis package targets ES2017/CommonJS and uses platform wrappers for crypto and request behavior. If your bundler complains about Node globals, check your bundler's CommonJS handling and runtime crypto support.\n\n## Limitations\n\n| Capability | Current State | Workaround |\n|------------|---------------|------------|\n| Hosted UI and OAuth redirects | Not included | Use Cognito Hosted UI, Amplify Auth, or your OAuth client. |\n| Admin Cognito APIs | Not included | Use AWS SDK admin APIs from trusted backend services. |\n| Full session manager | Not included | Store tokens/device metadata in your application layer. |\n| WebAuthn authentication flow | Preference settings are typed, but auth flow helpers are not implemented here. | Use Cognito-supported WebAuthn flows separately. |\n| SecretHash app clients | Not modeled across all operations. | Prefer public app clients for SRP flows or add server-side signing. |\n\n## FAQ\n\n### Is this a replacement for AWS Amplify Auth?\n\nNo. It is a focused Cognito helper package for teams that want direct control over SRP login and Cognito operations without adopting Amplify's broader framework.\n\n### Does Cogneato store tokens?\n\nNo. It returns tokens and device metadata to the caller. Your app chooses where and how to store them.\n\n### Can I use it in a browser?\n\nThe package exposes browser-compatible entry metadata and platform wrappers, but you should verify your bundler and runtime crypto support in your target browsers.\n\n### Does it support MFA?\n\nYes. `srpLogin()` handles software-token MFA and SMS MFA challenges. The package also includes helpers for associating, verifying, and preferring software-token MFA.\n\n### Does it support remembered devices?\n\nYes. Set `autoConfirmDevice: true` and `autoRememberDevice: \"remembered\"` to confirm and remember new devices, then persist the returned `newDevice` metadata for the next login.\n\n### Why is login an async generator?\n\nCognito auth is interactive. A single login may require MFA, a forced password update, or a device challenge. An async generator lets your app pause for user input and resume the same auth flow.\n\n### Where does this package live now?\n\nThe canonical source is the SaaSLayer monorepo:\n\n```text\n/packages/cogneato\n```\n\nRepository: https://github.com/DavidWells/saaslayer/tree/master/packages/cogneato\n\n### What is the project history?\n\nCogneato began as a fork of the [`franken-srp`](https://www.npmjs.com/package/franken-srp) package, then grew into a broader set of Cognito SRP login, device, MFA, account-operation, and identity-pool helpers.\n\nThe old standalone repository at https://github.com/DavidWells/cogneato is retained as a historical pointer only.\n\n## Development\n\n```bash\nnpm install\nnpm run build\nnpm test\n```\n\nIntegration-test helpers under `src/test/cdk` can deploy Cognito resources for live Cognito testing:\n\n```bash\nnpm run cdkdeploy\nnpm run createTestUsers\nnpm test\nnpm run cdkdestroy\n```\n\n## License\n\nMIT. See [LICENSE](./LICENSE).\n","readmeFilename":"README.md"}