@cogenta/auth 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/dist/audit.d.ts +17 -0
  2. package/dist/audit.d.ts.map +1 -0
  3. package/dist/audit.js +113 -0
  4. package/dist/audit.js.map +1 -0
  5. package/dist/credentials.d.ts +33 -0
  6. package/dist/credentials.d.ts.map +1 -0
  7. package/dist/credentials.js +95 -0
  8. package/dist/credentials.js.map +1 -0
  9. package/dist/index.d.ts +32 -0
  10. package/dist/index.d.ts.map +1 -0
  11. package/dist/index.js +23 -0
  12. package/dist/index.js.map +1 -0
  13. package/dist/login.d.ts +66 -0
  14. package/dist/login.d.ts.map +1 -0
  15. package/dist/login.js +300 -0
  16. package/dist/login.js.map +1 -0
  17. package/dist/mfa.d.ts +4 -0
  18. package/dist/mfa.d.ts.map +1 -0
  19. package/dist/mfa.js +28 -0
  20. package/dist/mfa.js.map +1 -0
  21. package/dist/password.d.ts +11 -0
  22. package/dist/password.d.ts.map +1 -0
  23. package/dist/password.js +108 -0
  24. package/dist/password.js.map +1 -0
  25. package/dist/rate-limit.d.ts +10 -0
  26. package/dist/rate-limit.d.ts.map +1 -0
  27. package/dist/rate-limit.js +47 -0
  28. package/dist/rate-limit.js.map +1 -0
  29. package/dist/sessions.d.ts +20 -0
  30. package/dist/sessions.d.ts.map +1 -0
  31. package/dist/sessions.js +82 -0
  32. package/dist/sessions.js.map +1 -0
  33. package/dist/store.d.ts +30 -0
  34. package/dist/store.d.ts.map +1 -0
  35. package/dist/store.js +27 -0
  36. package/dist/store.js.map +1 -0
  37. package/dist/tables.d.ts +17 -0
  38. package/dist/tables.d.ts.map +1 -0
  39. package/dist/tables.js +103 -0
  40. package/dist/tables.js.map +1 -0
  41. package/dist/totp.d.ts +22 -0
  42. package/dist/totp.d.ts.map +1 -0
  43. package/dist/totp.js +115 -0
  44. package/dist/totp.js.map +1 -0
  45. package/dist/types.d.ts +64 -0
  46. package/dist/types.d.ts.map +1 -0
  47. package/dist/types.js +11 -0
  48. package/dist/types.js.map +1 -0
  49. package/dist/users.d.ts +12 -0
  50. package/dist/users.d.ts.map +1 -0
  51. package/dist/users.js +69 -0
  52. package/dist/users.js.map +1 -0
  53. package/dist/webauthn.d.ts +40 -0
  54. package/dist/webauthn.d.ts.map +1 -0
  55. package/dist/webauthn.js +81 -0
  56. package/dist/webauthn.js.map +1 -0
  57. package/package.json +44 -0
@@ -0,0 +1,40 @@
1
+ import type { AuthenticationResponseJSON, PublicKeyCredentialCreationOptionsJSON, PublicKeyCredentialRequestOptionsJSON, RegistrationResponseJSON } from '@simplewebauthn/server';
2
+ import type { WebAuthnCredentialData } from './credentials.js';
3
+ /**
4
+ * WebAuthn is a dependency and TOTP is not, for the same reason the GraphQL
5
+ * executor is a dependency and the render cache is not: attestation
6
+ * verification — COSE key parsing, signature checks per algorithm, origin and
7
+ * RP ID validation — is a large, security-relevant surface every authenticator
8
+ * and browser expects to behave exactly like the spec, and a homegrown subset
9
+ * is a liability wearing the shape of a feature. `@simplewebauthn/server` is
10
+ * MIT, pure JS (no native code, rule R10 is clean), and is what the ecosystem
11
+ * has converged on.
12
+ *
13
+ * The ceremony is two requests apart — options generated, then a response
14
+ * verified — and needs a challenge to survive the gap. Storage for that
15
+ * challenge is deliberately not this module's job: it is single-use and lives
16
+ * seconds, which is a session or an in-memory cache at the API layer, not a
17
+ * database table alongside credentials that live for years.
18
+ */
19
+ export interface WebAuthnConfig {
20
+ readonly relyingPartyName: string;
21
+ /** The domain, no scheme and no port — `example.com`, not `https://example.com`. */
22
+ readonly relyingPartyId: string;
23
+ readonly origin: string;
24
+ }
25
+ export interface RegistrationOptions {
26
+ readonly options: PublicKeyCredentialCreationOptionsJSON;
27
+ readonly challenge: string;
28
+ }
29
+ export declare function beginWebAuthnRegistration(config: WebAuthnConfig, userId: string, userName: string, existing: readonly WebAuthnCredentialData[]): Promise<RegistrationOptions>;
30
+ export declare function completeWebAuthnRegistration(config: WebAuthnConfig, response: RegistrationResponseJSON, expectedChallenge: string, label: string | undefined): Promise<WebAuthnCredentialData>;
31
+ export interface AuthenticationOptions {
32
+ readonly options: PublicKeyCredentialRequestOptionsJSON;
33
+ readonly challenge: string;
34
+ }
35
+ export declare function beginWebAuthnAuthentication(config: WebAuthnConfig, allowed: readonly WebAuthnCredentialData[]): Promise<AuthenticationOptions>;
36
+ export interface WebAuthnAuthenticationResult {
37
+ readonly newCounter: number;
38
+ }
39
+ export declare function completeWebAuthnAuthentication(config: WebAuthnConfig, response: AuthenticationResponseJSON, expectedChallenge: string, credential: WebAuthnCredentialData): Promise<WebAuthnAuthenticationResult>;
40
+ //# sourceMappingURL=webauthn.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webauthn.d.ts","sourceRoot":"","sources":["../src/webauthn.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,0BAA0B,EAE1B,sCAAsC,EACtC,qCAAqC,EACrC,wBAAwB,EACzB,MAAM,wBAAwB,CAAA;AAO/B,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAA;AAE9D;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAA;IACjC,oFAAoF;IACpF,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAA;IAC/B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CACxB;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,OAAO,EAAE,sCAAsC,CAAA;IACxD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAC3B;AAED,wBAAsB,yBAAyB,CAC7C,MAAM,EAAE,cAAc,EACtB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,SAAS,sBAAsB,EAAE,GAC1C,OAAO,CAAC,mBAAmB,CAAC,CAe9B;AAED,wBAAsB,4BAA4B,CAChD,MAAM,EAAE,cAAc,EACtB,QAAQ,EAAE,wBAAwB,EAClC,iBAAiB,EAAE,MAAM,EACzB,KAAK,EAAE,MAAM,GAAG,SAAS,GACxB,OAAO,CAAC,sBAAsB,CAAC,CA4BjC;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,OAAO,EAAE,qCAAqC,CAAA;IACvD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAC3B;AAED,wBAAsB,2BAA2B,CAC/C,MAAM,EAAE,cAAc,EACtB,OAAO,EAAE,SAAS,sBAAsB,EAAE,GACzC,OAAO,CAAC,qBAAqB,CAAC,CAWhC;AAED,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;CAC5B;AAED,wBAAsB,8BAA8B,CAClD,MAAM,EAAE,cAAc,EACtB,QAAQ,EAAE,0BAA0B,EACpC,iBAAiB,EAAE,MAAM,EACzB,UAAU,EAAE,sBAAsB,GACjC,OAAO,CAAC,4BAA4B,CAAC,CA0BvC"}
@@ -0,0 +1,81 @@
1
+ import { CogentaError } from '@cogenta/core';
2
+ import { generateAuthenticationOptions, generateRegistrationOptions, verifyAuthenticationResponse, verifyRegistrationResponse, } from '@simplewebauthn/server';
3
+ export async function beginWebAuthnRegistration(config, userId, userName, existing) {
4
+ const options = await generateRegistrationOptions({
5
+ rpName: config.relyingPartyName,
6
+ rpID: config.relyingPartyId,
7
+ userID: new TextEncoder().encode(userId),
8
+ userName,
9
+ attestationType: 'none', // A site does not need to know *which* authenticator, only that one exists.
10
+ excludeCredentials: existing.map((credential) => ({
11
+ id: credential.credentialId,
12
+ transports: credential.transports,
13
+ })),
14
+ authenticatorSelection: { residentKey: 'preferred', userVerification: 'preferred' },
15
+ });
16
+ return { options, challenge: options.challenge };
17
+ }
18
+ export async function completeWebAuthnRegistration(config, response, expectedChallenge, label) {
19
+ // A malformed or forged response does not always fail through `verified:
20
+ // false` — the library also throws on input it cannot even parse (wrong
21
+ // shape, bad CBOR). Both paths mean the same thing to a caller: this
22
+ // registration did not succeed, as a typed error rather than a raw one.
23
+ const result = await verifyRegistrationResponse({
24
+ response,
25
+ expectedChallenge,
26
+ expectedOrigin: config.origin,
27
+ expectedRPID: config.relyingPartyId,
28
+ }).catch(() => null);
29
+ if (result === null || !result.verified) {
30
+ throw new CogentaError({
31
+ code: 'AUTH_WEBAUTHN_FAILED',
32
+ message: 'The authenticator response could not be verified.',
33
+ hint: 'Try registering the passkey again. If this keeps happening, the device clock or the site origin configuration may be wrong.',
34
+ });
35
+ }
36
+ const { credential } = result.registrationInfo;
37
+ return {
38
+ credentialId: credential.id,
39
+ publicKey: Buffer.from(credential.publicKey).toString('base64url'),
40
+ counter: credential.counter,
41
+ transports: credential.transports ?? [],
42
+ label,
43
+ };
44
+ }
45
+ export async function beginWebAuthnAuthentication(config, allowed) {
46
+ const options = await generateAuthenticationOptions({
47
+ rpID: config.relyingPartyId,
48
+ userVerification: 'preferred',
49
+ allowCredentials: allowed.map((credential) => ({
50
+ id: credential.credentialId,
51
+ transports: credential.transports,
52
+ })),
53
+ });
54
+ return { options, challenge: options.challenge };
55
+ }
56
+ export async function completeWebAuthnAuthentication(config, response, expectedChallenge, credential) {
57
+ // A counter that has not advanced since the last successful use is what a
58
+ // cloned authenticator looks like: refusing it is what makes cloning
59
+ // pointless rather than merely detectable after the fact.
60
+ const result = await verifyAuthenticationResponse({
61
+ response,
62
+ expectedChallenge,
63
+ expectedOrigin: config.origin,
64
+ expectedRPID: config.relyingPartyId,
65
+ credential: {
66
+ id: credential.credentialId,
67
+ publicKey: new Uint8Array(Buffer.from(credential.publicKey, 'base64url')),
68
+ counter: credential.counter,
69
+ transports: credential.transports,
70
+ },
71
+ }).catch(() => null);
72
+ if (result === null || !result.verified) {
73
+ throw new CogentaError({
74
+ code: 'AUTH_WEBAUTHN_FAILED',
75
+ message: 'The passkey response could not be verified.',
76
+ hint: 'Try again. If the passkey was moved to a new device or cloned, it will be refused on purpose — register a new one.',
77
+ });
78
+ }
79
+ return { newCounter: result.authenticationInfo.newCounter };
80
+ }
81
+ //# sourceMappingURL=webauthn.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webauthn.js","sourceRoot":"","sources":["../src/webauthn.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "@cogenta/auth",
3
+ "version": "0.1.0",
4
+ "description": "Identity, sessions and credentials: password, TOTP and WebAuthn, plus the append-only audit log.",
5
+ "license": "MPL-2.0",
6
+ "type": "module",
7
+ "sideEffects": false,
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "default": "./dist/index.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist"
16
+ ],
17
+ "engines": {
18
+ "node": ">=22.11.0"
19
+ },
20
+ "publishConfig": {
21
+ "access": "public",
22
+ "provenance": true
23
+ },
24
+ "repository": {
25
+ "type": "git",
26
+ "url": "git+https://github.com/cogenta-cms/cogenta.git",
27
+ "directory": "packages/auth"
28
+ },
29
+ "scripts": {
30
+ "build": "tsc -p tsconfig.json",
31
+ "typecheck": "tsc -p tsconfig.typecheck.json",
32
+ "test": "vitest run --passWithNoTests",
33
+ "test:integration": "vitest run --config vitest.integration.config.ts --passWithNoTests"
34
+ },
35
+ "dependencies": {
36
+ "@cogenta/core": "workspace:*",
37
+ "@cogenta/schema": "workspace:*",
38
+ "@simplewebauthn/server": "catalog:"
39
+ },
40
+ "devDependencies": {
41
+ "typescript": "catalog:",
42
+ "vitest": "catalog:"
43
+ }
44
+ }