{"_id":"@credocentral/e-identity-core","_rev":"3-aa88c16d142886534d5b3de732867f39","name":"@credocentral/e-identity-core","dist-tags":{"latest":"1.0.2"},"versions":{"1.0.0":{"name":"@credocentral/e-identity-core","version":"1.0.0","keywords":["oauth2","pkce","e-identity","etranzact"],"license":"MIT","_id":"@credocentral/e-identity-core@1.0.0","maintainers":[{"name":"valenteeena","email":"toun.olayemi2@gmail.com"},{"name":"stephen.obi","email":"hello@credocentral.com"}],"dist":{"shasum":"2b68d81ef5bbe6ba8a6ecfb878b47ffc57d9b3b6","tarball":"https://registry.npmjs.org/@credocentral/e-identity-core/-/e-identity-core-1.0.0.tgz","fileCount":7,"integrity":"sha512-ypS6cXVgJQzuivSbTnRB/9RAvakZoluwpYDatRjhrcfyAAEabIN+6oIw5AEaDSAI74tvrL8Iz+zIRXZ8zD5Ybg==","signatures":[{"sig":"MEUCIB7lifDofVVOKF2xoqSkKE2QlSqoWAS6SddZODX/vGXHAiEA65z5WMJ4Mj1GAwqYUg6G8zCMWKfi5i9pjsqGQomEPoo=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":80566},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"}},"gitHead":"dddee3f3c6d07f72b8a94b9ac47a7dfde28eea82","scripts":{"test":"vitest run","build":"tsup","clean":"rm -rf dist","typecheck":"tsc --noEmit"},"_npmUser":{"name":"stephen.obi","email":"hello@credocentral.com"},"_npmVersion":"10.9.7","description":"Core PKCE, state, token storage, and API client for the e-identity SDK","directories":{},"_nodeVersion":"22.22.2","_hasShrinkwrap":false,"devDependencies":{"tsup":"*","vitest":"*","typescript":"*","@types/node":"*"},"_npmOperationalInternal":{"tmp":"tmp/e-identity-core_1.0.0_1779220508330_0.4311701897038469","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@credocentral/e-identity-core","version":"1.0.1","keywords":["oauth2","pkce","e-identity","etranzact"],"license":"MIT","_id":"@credocentral/e-identity-core@1.0.1","maintainers":[{"name":"valenteeena","email":"toun.olayemi2@gmail.com"},{"name":"stephen.obi","email":"hello@credocentral.com"}],"dist":{"shasum":"96e3fbb76764ac57a91fba6acdd5ee4dca6b6bcf","tarball":"https://registry.npmjs.org/@credocentral/e-identity-core/-/e-identity-core-1.0.1.tgz","fileCount":8,"integrity":"sha512-7tf/gCYzdb9tWCSBWOjjPNjuJII2UYUL+DVuZFeKW4eAYu/ToEb9vRuoVQYJZtZ2K4eocU8Q4zVfzl2XGlifsw==","signatures":[{"sig":"MEUCIE2r7dNpK/jAhvYGTyWtxbfI7MEkSe+9TcjeKE/Wi9e2AiEAmedQluKepLta28cNJZ9Vml9oojKLn41ymfb33YGdzpE=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":89680},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"}},"gitHead":"d1c285127e9bc1239152e2004ef7dca72dbc701a","scripts":{"test":"vitest run","build":"tsup","clean":"rm -rf dist","typecheck":"tsc --noEmit"},"_npmUser":{"name":"stephen.obi","email":"hello@credocentral.com"},"_npmVersion":"10.9.7","description":"Core PKCE, state, token storage, and API client for the e-identity SDK","directories":{},"_nodeVersion":"22.22.2","_hasShrinkwrap":false,"devDependencies":{"tsup":"*","vitest":"*","typescript":"*","@types/node":"*"},"_npmOperationalInternal":{"tmp":"tmp/e-identity-core_1.0.1_1779225149607_0.3795699165348212","host":"s3://npm-registry-packages-npm-production"}},"1.0.2":{"name":"@credocentral/e-identity-core","version":"1.0.2","description":"Core PKCE, state, token storage, and API client for the e-identity SDK","keywords":["oauth2","pkce","e-identity","etranzact"],"license":"MIT","type":"module","main":"./dist/index.cjs","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"import":"./dist/index.js","require":"./dist/index.cjs","types":"./dist/index.d.ts"}},"scripts":{"build":"tsup","typecheck":"tsc --noEmit","test":"vitest run","clean":"rm -rf dist"},"devDependencies":{"tsup":"*","typescript":"*","vitest":"*","@types/node":"*"},"_id":"@credocentral/e-identity-core@1.0.2","gitHead":"657a1038da2e8b8a04600dbc7aaaef2d3b16cd5a","_nodeVersion":"22.22.2","_npmVersion":"10.9.7","dist":{"integrity":"sha512-G6h7EVNu+DNtR6aHK+2ujgwreO2I6ZzXQd6iOCKv0UiHAE3330IlWSRyt3PhL9Oa3Ff8ttR6U1RR2gvIqxSkKg==","shasum":"012920aad6eef4c98d3cdec1688ab3a674d96d7e","tarball":"https://registry.npmjs.org/@credocentral/e-identity-core/-/e-identity-core-1.0.2.tgz","fileCount":8,"unpackedSize":93564,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCnQpeIvivIuNVDLJgdGmQwkjpe62zg2RgPk4+gl8ZibQIgc6k/yczLndet5Nc8b6o27GBO0cj5D/yzkyV8kNaMEhE="}]},"_npmUser":{"name":"stephen.obi","email":"stephen.obi@etranzact.com"},"directories":{},"maintainers":[{"name":"valenteeena","email":"toun.olayemi2@gmail.com"},{"name":"stephen.obi","email":"stephen.obi@etranzact.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/e-identity-core_1.0.2_1779467027608_0.6067687156358281"},"_hasShrinkwrap":false}},"time":{"created":"2026-05-19T19:55:08.206Z","modified":"2026-05-22T16:23:47.931Z","1.0.0":"2026-05-19T19:55:08.517Z","1.0.1":"2026-05-19T21:12:29.766Z","1.0.2":"2026-05-22T16:23:47.752Z"},"license":"MIT","keywords":["oauth2","pkce","e-identity","etranzact"],"description":"Core PKCE, state, token storage, and API client for the e-identity SDK","maintainers":[{"name":"valenteeena","email":"toun.olayemi2@gmail.com"},{"name":"stephen.obi","email":"stephen.obi@etranzact.com"}],"readme":"# @credocentral/e-identity-core\n\nCore primitives for the **e-identity** SDK — PKCE helpers, state/nonce generation, token storage, JWT parsing, and the full API client. Framework-agnostic; works in browsers, Node.js, and React Native.\n\nThis package is consumed by `@credocentral/e-identity-react`, `@credocentral/e-identity-nextjs`, and `@credocentral/e-identity-react-native`. You only need to install it directly if you are building a custom integration.\n\n## Installation\n\n```sh\nnpm install @credocentral/e-identity-core\n```\n\nNo peer dependencies. Requires an environment with the Web Crypto API (`crypto.subtle`, `crypto.getRandomValues`) — available natively in browsers, Node 19+, and React Native via `react-native-get-random-values`.\n\n## Quick Start\n\n```ts\nimport {\n  generateVerifier, generateChallenge, generateState, generateNonce,\n  EIdentityApiClient,\n  parseUser, isTokenExpired,\n  createTokenStorage,\n} from '@credocentral/e-identity-core';\n\n// Build a PKCE authorization URL\nconst verifier = generateVerifier();\nconst challenge = await generateChallenge(verifier);\nconst state = generateState();\nconst nonce = generateNonce();\n\nconst params = new URLSearchParams({\n  response_type: 'code',\n  client_id: 'your-app-uuid',\n  redirect_uri: 'https://app.example.com/auth/callback',\n  scope: 'openid profile email',\n  state, nonce,\n  code_challenge: challenge,\n  code_challenge_method: 'S256',\n});\n\nwindow.location.href = `https://id.example.com/identity/authorize?${params}`;\n\n// Exchange the code after redirect\nconst client = new EIdentityApiClient({ issuerUrl: 'https://id.example.com' });\nconst tokens = await client.exchangeCode({\n  clientId: 'your-app-uuid',\n  code: 'auth-code-from-callback',\n  codeVerifier: verifier,\n  redirectUri: 'https://app.example.com/auth/callback',\n});\n\nconst user = parseUser(tokens.accessToken);\nconsole.log(user.sub, user.emailAddress);\n```\n\n## PKCE Utilities\n\n```ts\nimport { generateVerifier, generateChallenge, base64UrlEncode } from '@credocentral/e-identity-core';\n```\n\n| Function | Signature | Description |\n|---|---|---|\n| `generateVerifier` | `(length?: number) => string` | Cryptographically random code verifier (default 64 chars, URL-safe) |\n| `generateChallenge` | `(verifier: string) => Promise<string>` | SHA-256 hash of the verifier, base64url-encoded (S256 method) |\n| `base64UrlEncode` | `(buffer: Uint8Array) => string` | Base64url encoding without padding |\n\n## State & Nonce Utilities\n\n```ts\nimport { generateState, generateNonce, validateState } from '@credocentral/e-identity-core';\n```\n\n| Function | Signature | Description |\n|---|---|---|\n| `generateState` | `() => string` | 32-byte random base64url string for CSRF protection |\n| `generateNonce` | `() => string` | 16-byte random base64url string for replay protection |\n| `validateState` | `(expected: string, received: string) => boolean` | Constant-time equality check for state parameter |\n\n## Token Storage\n\n```ts\nimport { createTokenStorage, MemoryTokenStorage, SessionStorageTokenStorage } from '@credocentral/e-identity-core';\nimport type { TokenStorage } from '@credocentral/e-identity-core';\n```\n\n| Class / Function | Description |\n|---|---|\n| `MemoryTokenStorage` | In-process storage; tokens lost on page reload. Safest option. |\n| `SessionStorageTokenStorage` | `sessionStorage`-backed; survives page refresh within the same tab. |\n| `createTokenStorage(type)` | Factory: `'memory'` → `MemoryTokenStorage`, `'sessionStorage'` → `SessionStorageTokenStorage` |\n\nAll storage classes implement the `TokenStorage` interface:\n\n```ts\ninterface TokenStorage {\n  getTokens(): TokenSet | null;\n  setTokens(tokens: TokenSet): void;\n  clearTokens(): void;\n}\n```\n\n## Token Parser\n\n```ts\nimport { parseJwtPayload, parseUser, isTokenExpired } from '@credocentral/e-identity-core';\n```\n\n| Function | Signature | Description |\n|---|---|---|\n| `parseJwtPayload` | `(token: string) => Record<string, unknown>` | Decode JWT payload without verification (client-side only) |\n| `parseUser` | `(accessToken: string) => User` | Parse the access token and cast claims to the `User` type |\n| `isTokenExpired` | `(expiresAt: number, bufferSeconds?: number) => boolean` | Returns `true` when `now >= expiresAt - buffer` (default buffer 30 s) |\n\n## `EIdentityApiClient`\n\n```ts\nimport { EIdentityApiClient } from '@credocentral/e-identity-core';\n\nconst client = new EIdentityApiClient({ issuerUrl: 'https://id.example.com' });\n```\n\n### OAuth2 / Token Methods\n\n| Method | Description |\n|---|---|\n| `getLoginConfig(appId)` | Fetch branding and allowed login methods for an application |\n| `exchangeCode({ clientId, code, codeVerifier, redirectUri })` | Authorization Code + PKCE token exchange |\n| `refreshTokens({ clientId, refreshToken })` | Refresh access token using a refresh token |\n| `revokeToken({ clientId, token, tokenTypeHint? })` | Revoke an access or refresh token |\n\n### MFA Challenge (public — no access token required)\n\nThese are called during the login flow when the server returns a `challengeToken` instead of tokens.\n\n| Method | Description |\n|---|---|\n| `verifyTotpChallenge({ challengeToken, code })` | Verify a 6-digit TOTP code |\n| `verifyOtpChallenge({ challengeToken, code })` | Verify an email/SMS OTP code |\n| `resendOtpChallenge({ challengeToken })` | Resend OTP; returns `{ maskedDestination }` |\n| `verifyRecoveryCode({ challengeToken, recoveryCode })` | Use a backup recovery code |\n| `getPasskeyChallengeOptions({ challengeToken })` | Fetch WebAuthn `get()` options JSON |\n| `verifyPasskeyChallenge({ challengeToken, responseJson })` | Submit WebAuthn assertion response |\n\nAll challenge methods return a `TokenSet` on success (promoting the session to AAL2), or throw an `Error` with the server's error code as the message (e.g. `INVALID_MFA_CODE`, `CHALLENGE_TOKEN_INVALID`).\n\n### MFA Enrollment (authenticated — requires access token)\n\n| Method | Description |\n|---|---|\n| `enrollTotpOptions(accessToken)` | Start TOTP enrollment; returns `{ setupToken, qrCodeDataUri, secret }` |\n| `confirmTotpEnrollment(accessToken, { setupToken, code })` | Confirm TOTP with a valid code; returns `{ recoveryCodes }` |\n| `enrollPasskeyOptions(accessToken)` | Start passkey registration; returns `{ setupToken, optionsJson }` |\n| `confirmPasskeyEnrollment(accessToken, { setupToken, responseJson })` | Submit WebAuthn registration response |\n\n### MFA Management (authenticated)\n\n| Method | Description |\n|---|---|\n| `listMfaMethods(accessToken)` | List enrolled MFA methods with status and recovery code counts |\n| `regenerateRecoveryCodes(accessToken)` | Generate a new set of recovery codes (invalidates the old set) |\n\n## Types\n\n```ts\nimport type {\n  EIdentityConfig,\n  TokenSet,\n  User,\n  AcrValue,\n  MfaMethodType,\n  MfaMethodSummary,\n  LoginConfig,\n  MosResponse,\n  AuthorizationParams,\n} from '@credocentral/e-identity-core';\n```\n\n### `EIdentityConfig`\n\n| Field | Type | Description |\n|---|---|---|\n| `issuerUrl` | `string` | Base URL of the e-identity server |\n| `appId` | `string` | Application UUID (`appAId`) |\n| `redirectUri` | `string` | Registered OAuth2 callback URL |\n| `scopes?` | `string[]` | Defaults to `['openid', 'profile', 'email']` |\n| `tokenStorage?` | `'memory' \\| 'sessionStorage'` | Storage backend for tokens |\n\n### `TokenSet`\n\n| Field | Type | Description |\n|---|---|---|\n| `accessToken` | `string` | JWT access token |\n| `idToken?` | `string` | OIDC ID token (present on initial exchange) |\n| `refreshToken?` | `string` | Refresh token (offline_access scope required) |\n| `expiresIn` | `number` | Lifetime in seconds |\n| `expiresAt` | `number` | Absolute Unix timestamp (seconds) — use with `isTokenExpired` |\n| `tokenType` | `string` | Always `'Bearer'` |\n| `scope?` | `string` | Granted scopes |\n\n### `User`\n\nKey claims parsed from the access token. Additional custom claims are available via the index signature `[claim: string]: unknown`.\n\n| Claim | Type | Description |\n|---|---|---|\n| `sub` | `string` | Subject identifier |\n| `userId?` | `number` | Internal user ID |\n| `emailAddress?` | `string` | User's email |\n| `phoneNumber?` | `string` | User's phone |\n| `twoFaEnabledAuth?` | `number` | `1` when MFA is enabled on the account |\n| `mfa_verified?` | `boolean` | `true` on AAL2 tokens (MFA completed this session) |\n| `forcePasswordChange?` | `number` | `1` when the user must change their password |\n| `acr?` | `string` | Authentication Context Reference (`'aal1'` or `'aal2'`) |\n| `amr?` | `string[]` | Authentication Method References (e.g. `['pwd', 'totp', 'mfa']`) |\n| `pb_roles?` | `Record<string, Record<string, string>>` | Product-scoped RBAC roles |\n| `products?` | `string[]` | Products the user has access to |\n\n### `MfaMethodSummary`\n\nReturned by `listMfaMethods`:\n\n```ts\ninterface MfaMethodSummary {\n  method: 'TOTP' | 'EMAIL_OTP' | 'SMS_OTP' | 'PASSKEY';\n  active: boolean;\n  enrolledAt: string | null;\n  recoveryCodesRemaining: number | null;\n}\n```\n\n## Requirements\n\n- Web Crypto API (`crypto.subtle`, `crypto.getRandomValues`)\n- Browser, Node.js 19+, or React Native with `react-native-get-random-values`\n","readmeFilename":"README.md"}