3 Commits

Author SHA1 Message Date
jkunz 4702f500a9 v1.1.0 2026-05-19 06:26:14 +00:00
jkunz 78c7c4c814 docs(changelog): note MFA contract additions 2026-05-19 06:26:03 +00:00
jkunz 8746bc083e feat(interfaces): add MFA and passkey contracts 2026-05-19 06:24:06 +00:00
10 changed files with 329 additions and 3 deletions
+9
View File
@@ -3,6 +3,15 @@
## Pending
## 2026-05-19 - 1.1.0
### Features
- add MFA and passkey typed request contracts (interfaces)
- adds TOTP, backup code, MFA challenge, passkey credential, and WebAuthn challenge data contracts
- extends login responses with MFA challenge metadata for password and magic-link flows
- exports typed request contracts for TOTP enrollment, backup codes, passkey login, and passkey MFA step-up
## 2026-05-18 - 1.0.1
### Fixes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@idp.global/interfaces",
"version": "1.0.1",
"version": "1.1.0",
"private": false,
"description": "Shared TypeScript interfaces and TypedRequest contracts for the idp.global ecosystem.",
"exports": {
+1 -1
View File
@@ -3,6 +3,6 @@
*/
export const commitinfo = {
name: '@idp.global/interfaces',
version: '1.0.1',
version: '1.1.0',
description: 'Shared TypeScript interfaces and TypedRequest contracts for the idp.global ecosystem.'
}
+7
View File
@@ -16,6 +16,13 @@ export type TActivityAction =
| 'role_changed'
| 'org_app_role_mappings_updated'
| 'profile_updated'
| 'totp_enabled'
| 'totp_disabled'
| 'backup_codes_regenerated'
| 'mfa_completed'
| 'passkey_registered'
| 'passkey_revoked'
| 'passkey_login'
| 'app_connected'
| 'app_disconnected';
+2
View File
@@ -10,8 +10,10 @@ export * from './billingplan.js';
export * from './device.js';
export * from './jwt.js';
export * from './loginsession.js';
export * from './mfa.js';
export * from './organization.js';
export * from './paddlecheckoutdata.js';
export * from './passkey.js';
export * from './passportchallenge.js';
export * from './passportdevice.js';
export * from './passportnonce.js';
+45
View File
@@ -0,0 +1,45 @@
export type TMfaMethod = 'totp' | 'backupCode' | 'passkey';
export type TMfaChallengeStatus = 'pending' | 'completed' | 'expired';
export type TTotpCredentialStatus = 'pending' | 'active' | 'disabled';
export interface ITotpBackupCode {
id: string;
codeHash: string;
usedAt?: number | null;
createdAt: number;
}
export interface ITotpCredential {
id: string;
data: {
userId: string;
status: TTotpCredentialStatus;
secretCiphertext: string;
secretIv: string;
secretAuthTag: string;
algorithm: 'sha1' | 'sha256' | 'sha512';
digits: 6 | 7 | 8;
period: number;
backupCodes: ITotpBackupCode[];
createdAt: number;
verifiedAt?: number | null;
disabledAt?: number | null;
lastUsedAt?: number | null;
};
}
export interface IMfaChallenge {
id: string;
data: {
userId: string;
tokenHash: string;
status: TMfaChallengeStatus;
availableMethods: TMfaMethod[];
primaryAuthMethod: 'password' | 'email';
createdAt: number;
expiresAt: number;
completedAt?: number | null;
};
}
+49
View File
@@ -0,0 +1,49 @@
export type TPasskeyCredentialStatus = 'active' | 'revoked';
export type TPasskeyChallengeType = 'registration' | 'login' | 'mfa';
export type TPasskeyChallengeStatus = 'pending' | 'completed' | 'expired';
export type TPasskeyTransport =
| 'ble'
| 'cable'
| 'hybrid'
| 'internal'
| 'nfc'
| 'smart-card'
| 'usb';
export type TPasskeyDeviceType = 'singleDevice' | 'multiDevice';
export interface IPasskeyCredential {
id: string;
data: {
userId: string;
label: string;
credentialId: string;
publicKeyBase64: string;
counter: number;
deviceType: TPasskeyDeviceType;
backedUp: boolean;
transports?: TPasskeyTransport[];
status: TPasskeyCredentialStatus;
createdAt: number;
lastUsedAt?: number | null;
revokedAt?: number | null;
};
}
export interface IWebAuthnChallenge {
id: string;
data: {
userId?: string | null;
username?: string | null;
mfaChallengeId?: string | null;
type: TPasskeyChallengeType;
challenge: string;
status: TPasskeyChallengeStatus;
createdAt: number;
expiresAt: number;
completedAt?: number | null;
};
}
+1
View File
@@ -6,6 +6,7 @@ export * from './authorization.js';
export * from './billingplan.js';
export * from './jwt.js';
export * from './login.js';
export * from './mfa.js';
export * from './organization.js';
export * from './passport.js';
export * from './plan.js';
+6 -1
View File
@@ -14,6 +14,8 @@ export interface IReq_LoginWithEmailOrUsernameAndPassword
response: {
refreshToken?: string;
twoFaNeeded: boolean;
mfaChallengeToken?: string;
availableMfaMethods?: data.TMfaMethod[];
};
}
@@ -43,7 +45,10 @@ export interface IReq_LoginWithEmailAfterEmailTokenAquired
token: string;
};
response: {
refreshToken: string;
refreshToken?: string;
twoFaNeeded?: boolean;
mfaChallengeToken?: string;
availableMfaMethods?: data.TMfaMethod[];
};
}
+208
View File
@@ -0,0 +1,208 @@
import * as plugins from '../plugins.js';
import * as data from '../data/index.js';
export interface IReq_GetMfaStatus
extends plugins.typedRequestInterfaces.implementsTR<
plugins.typedRequestInterfaces.ITypedRequest,
IReq_GetMfaStatus
> {
method: 'getMfaStatus';
request: {
jwt: string;
};
response: {
totpEnabled: boolean;
backupCodesRemaining: number;
passkeys: data.IPasskeyCredential[];
availableMethods: data.TMfaMethod[];
};
}
export interface IReq_StartTotpEnrollment
extends plugins.typedRequestInterfaces.implementsTR<
plugins.typedRequestInterfaces.ITypedRequest,
IReq_StartTotpEnrollment
> {
method: 'startTotpEnrollment';
request: {
jwt: string;
};
response: {
credentialId: string;
secret: string;
otpauthUrl: string;
};
}
export interface IReq_FinishTotpEnrollment
extends plugins.typedRequestInterfaces.implementsTR<
plugins.typedRequestInterfaces.ITypedRequest,
IReq_FinishTotpEnrollment
> {
method: 'finishTotpEnrollment';
request: {
jwt: string;
credentialId: string;
code: string;
};
response: {
success: boolean;
backupCodes: string[];
};
}
export interface IReq_DisableTotp
extends plugins.typedRequestInterfaces.implementsTR<
plugins.typedRequestInterfaces.ITypedRequest,
IReq_DisableTotp
> {
method: 'disableTotp';
request: {
jwt: string;
code: string;
};
response: {
success: boolean;
};
}
export interface IReq_RegenerateBackupCodes
extends plugins.typedRequestInterfaces.implementsTR<
plugins.typedRequestInterfaces.ITypedRequest,
IReq_RegenerateBackupCodes
> {
method: 'regenerateBackupCodes';
request: {
jwt: string;
code: string;
};
response: {
backupCodes: string[];
};
}
export interface IReq_VerifyMfaChallenge
extends plugins.typedRequestInterfaces.implementsTR<
plugins.typedRequestInterfaces.ITypedRequest,
IReq_VerifyMfaChallenge
> {
method: 'verifyMfaChallenge';
request: {
mfaChallengeToken: string;
method: Extract<data.TMfaMethod, 'totp' | 'backupCode'>;
code: string;
};
response: {
refreshToken: string;
};
}
export interface IReq_StartPasskeyRegistration
extends plugins.typedRequestInterfaces.implementsTR<
plugins.typedRequestInterfaces.ITypedRequest,
IReq_StartPasskeyRegistration
> {
method: 'startPasskeyRegistration';
request: {
jwt: string;
label?: string;
};
response: {
challengeId: string;
options: Record<string, any>;
};
}
export interface IReq_FinishPasskeyRegistration
extends plugins.typedRequestInterfaces.implementsTR<
plugins.typedRequestInterfaces.ITypedRequest,
IReq_FinishPasskeyRegistration
> {
method: 'finishPasskeyRegistration';
request: {
jwt: string;
challengeId: string;
label?: string;
response: Record<string, any>;
};
response: {
success: boolean;
passkey: data.IPasskeyCredential;
};
}
export interface IReq_RevokePasskey
extends plugins.typedRequestInterfaces.implementsTR<
plugins.typedRequestInterfaces.ITypedRequest,
IReq_RevokePasskey
> {
method: 'revokePasskey';
request: {
jwt: string;
passkeyId: string;
};
response: {
success: boolean;
};
}
export interface IReq_StartPasskeyLogin
extends plugins.typedRequestInterfaces.implementsTR<
plugins.typedRequestInterfaces.ITypedRequest,
IReq_StartPasskeyLogin
> {
method: 'startPasskeyLogin';
request: {
username?: string;
};
response: {
challengeId: string;
options: Record<string, any>;
};
}
export interface IReq_FinishPasskeyLogin
extends plugins.typedRequestInterfaces.implementsTR<
plugins.typedRequestInterfaces.ITypedRequest,
IReq_FinishPasskeyLogin
> {
method: 'finishPasskeyLogin';
request: {
challengeId: string;
response: Record<string, any>;
};
response: {
refreshToken: string;
};
}
export interface IReq_StartPasskeyMfa
extends plugins.typedRequestInterfaces.implementsTR<
plugins.typedRequestInterfaces.ITypedRequest,
IReq_StartPasskeyMfa
> {
method: 'startPasskeyMfa';
request: {
mfaChallengeToken: string;
};
response: {
challengeId: string;
options: Record<string, any>;
};
}
export interface IReq_FinishPasskeyMfa
extends plugins.typedRequestInterfaces.implementsTR<
plugins.typedRequestInterfaces.ITypedRequest,
IReq_FinishPasskeyMfa
> {
method: 'finishPasskeyMfa';
request: {
mfaChallengeToken: string;
challengeId: string;
response: Record<string, any>;
};
response: {
refreshToken: string;
};
}