diff --git a/packages/authgear-core/src/types.test.ts b/packages/authgear-core/src/types.test.ts index 5020fd3c..6775f17c 100644 --- a/packages/authgear-core/src/types.test.ts +++ b/packages/authgear-core/src/types.test.ts @@ -1,4 +1,4 @@ -import { _decodeUserInfo } from "./types"; +import { _decodeUserInfo, AuthenticatorType, AuthenticatorKind } from "./types"; const USER_INFO = ` { @@ -7,6 +7,33 @@ const USER_INFO = ` "https://authgear.com/claims/user/is_anonymous": false, "https://authgear.com/claims/user/can_reauthenticate": true, "https://authgear.com/claims/user/roles": ["role_a"], + "https://authgear.com/claims/user/authenticators": [ + { + "created_at": "2023-01-01T00:00:00Z", + "updated_at": "2023-01-01T00:00:00Z", + "type": "password", + "kind": "primary" + }, + { + "created_at": "2023-01-01T00:00:00Z", + "updated_at": "2023-01-01T00:00:00Z", + "type": "oob_otp_sms", + "kind": "primary" + }, + { + "created_at": "2023-01-01T00:00:00Z", + "updated_at": "2023-01-01T00:00:00Z", + "type": "oob_otp_email", + "kind": "primary" + }, + { + "created_at": "2023-01-01T00:00:00Z", + "updated_at": "2023-01-01T00:00:00Z", + "type": "totp", + "kind": "secondary" + } + ], + "https://authgear.com/claims/user/recovery_code_enabled": true, "email": "user@example.com", "email_verified": true, @@ -55,6 +82,33 @@ describe("_decodeUserInfo", () => { birthdate: "1970-01-01", canReauthenticate: true, roles: ["role_a"], + authenticators: [ + { + createdAt: new Date("2023-01-01T00:00:00Z"), + updatedAt: new Date("2023-01-01T00:00:00Z"), + type: AuthenticatorType.Password, + kind: AuthenticatorKind.Primary, + }, + { + createdAt: new Date("2023-01-01T00:00:00Z"), + updatedAt: new Date("2023-01-01T00:00:00Z"), + type: AuthenticatorType.OOBOTPSMS, + kind: AuthenticatorKind.Primary, + }, + { + createdAt: new Date("2023-01-01T00:00:00Z"), + updatedAt: new Date("2023-01-01T00:00:00Z"), + type: AuthenticatorType.OOBOTPEmail, + kind: AuthenticatorKind.Primary, + }, + { + createdAt: new Date("2023-01-01T00:00:00Z"), + updatedAt: new Date("2023-01-01T00:00:00Z"), + type: AuthenticatorType.TOTP, + kind: AuthenticatorKind.Secondary, + }, + ], + recoveryCodeEnabled: true, customAttributes: { foobar: 42, }, @@ -84,6 +138,33 @@ describe("_decodeUserInfo", () => { street_address: "10 Somewhere Street", }, birthdate: "1970-01-01", + "https://authgear.com/claims/user/authenticators": [ + { + created_at: "2023-01-01T00:00:00Z", + updated_at: "2023-01-01T00:00:00Z", + type: "password", + kind: "primary", + }, + { + created_at: "2023-01-01T00:00:00Z", + updated_at: "2023-01-01T00:00:00Z", + type: "oob_otp_sms", + kind: "primary", + }, + { + created_at: "2023-01-01T00:00:00Z", + updated_at: "2023-01-01T00:00:00Z", + type: "oob_otp_email", + kind: "primary", + }, + { + created_at: "2023-01-01T00:00:00Z", + updated_at: "2023-01-01T00:00:00Z", + type: "totp", + kind: "secondary", + }, + ], + "https://authgear.com/claims/user/recovery_code_enabled": true, custom_attributes: { foobar: 42, }, diff --git a/packages/authgear-core/src/types.ts b/packages/authgear-core/src/types.ts index f0c0c5d6..859fec88 100644 --- a/packages/authgear-core/src/types.ts +++ b/packages/authgear-core/src/types.ts @@ -1,3 +1,31 @@ +/** + * @public + */ +export enum AuthenticatorType { + Password = "password", + OOBOTPEmail = "oob_otp_email", + OOBOTPSMS = "oob_otp_sms", + TOTP = "totp", +} + +/** + * @public + */ +export enum AuthenticatorKind { + Primary = "primary", + Secondary = "secondary", +} + +/** + * @public + */ +export interface Authenticator { + createdAt: Date; + updatedAt: Date; + type: AuthenticatorType; + kind: AuthenticatorKind; +} + /** * UserInfo is the result of fetchUserInfo. * It contains `sub` which is the User ID, @@ -14,6 +42,7 @@ export interface UserInfo { isVerified: boolean; isAnonymous: boolean; canReauthenticate: boolean; + recoveryCodeEnabled?: boolean; roles?: string[]; raw: Record; @@ -44,6 +73,7 @@ export interface UserInfo { postalCode?: string; country?: string; }; + authenticators?: Authenticator[]; } /** @@ -173,6 +203,23 @@ export interface _APIClientDelegate { refreshAccessTokenIfNeeded(): Promise; } +/** + * @internal + */ +export function _decodeAuthenticators(r: any): Authenticator[] | undefined { + if (!Array.isArray(r)) { + return undefined; + } + return r.map((a) => { + return { + createdAt: new Date(a["created_at"]), + updatedAt: new Date(a["updated_at"]), + type: a["type"], + kind: a["kind"], + }; + }); +} + /** * @internal */ @@ -186,7 +233,12 @@ export function _decodeUserInfo(r: any): UserInfo { isAnonymous: r["https://authgear.com/claims/user/is_anonymous"] ?? false, canReauthenticate: r["https://authgear.com/claims/user/can_reauthenticate"] ?? false, + recoveryCodeEnabled: + r["https://authgear.com/claims/user/recovery_code_enabled"] ?? false, roles: r["https://authgear.com/claims/user/roles"], + authenticators: _decodeAuthenticators( + r["https://authgear.com/claims/user/authenticators"] + ), raw, customAttributes,