diff --git a/packages/core/src/libraries/verification.ts b/packages/core/src/libraries/verification.ts index cd4869706..cdd414a57 100644 --- a/packages/core/src/libraries/verification.ts +++ b/packages/core/src/libraries/verification.ts @@ -1,4 +1,3 @@ -import RequestError from '../errors/RequestError/index.js'; import { expirationTime } from '../queries/verification-records.js'; import { buildVerificationRecord, @@ -43,34 +42,6 @@ const getVerificationRecordById = async ({ return buildVerificationRecord(libraries, queries, result.data); }; -/** - * Verifies the user sensitive permission by checking if the verification record is valid - * and associated with the user. - */ -export const verifyUserSensitivePermission = async ({ - userId, - id, - queries, - libraries, -}: { - userId: string; - id: string; - queries: Queries; - libraries: Libraries; -}): Promise => { - try { - const record = await getVerificationRecordById({ id, queries, libraries, userId }); - - assertThat(record.isVerified, 'verification_record.not_found'); - } catch (error) { - if (error instanceof RequestError) { - throw new RequestError({ code: 'verification_record.permission_denied', status: 401 }); - } - - throw error; - } -}; - /** * Builds a user verification record by its id and type. * This is used to build a verification record for new identifier verifications, diff --git a/packages/core/src/middleware/koa-auth/constants.ts b/packages/core/src/middleware/koa-auth/constants.ts new file mode 100644 index 000000000..d707403bf --- /dev/null +++ b/packages/core/src/middleware/koa-auth/constants.ts @@ -0,0 +1 @@ +export const verificationRecordIdHeader = 'logto-verification-id'; diff --git a/packages/core/src/middleware/koa-auth/index.ts b/packages/core/src/middleware/koa-auth/index.ts index ca7d9916f..98e1f42ff 100644 --- a/packages/core/src/middleware/koa-auth/index.ts +++ b/packages/core/src/middleware/koa-auth/index.ts @@ -16,6 +16,7 @@ import { type WithAuthContext, type TokenInfo } from './types.js'; import { extractBearerTokenFromHeaders, getAdminTenantTokenValidationSet } from './utils.js'; export * from './types.js'; +export * from './constants.js'; export const verifyBearerTokenFromRequest = async ( envSet: EnvSet, diff --git a/packages/core/src/middleware/koa-auth/koa-oidc-auth.test.ts b/packages/core/src/middleware/koa-auth/koa-oidc-auth.test.ts index 1fe5967f6..787f31088 100644 --- a/packages/core/src/middleware/koa-auth/koa-oidc-auth.test.ts +++ b/packages/core/src/middleware/koa-auth/koa-oidc-auth.test.ts @@ -7,11 +7,15 @@ import Sinon from 'sinon'; import RequestError from '#src/errors/RequestError/index.js'; import { createContextWithRouteParameters } from '#src/utils/test-utils.js'; +import { MockTenant } from '../../test-utils/tenant.js'; + import type { WithAuthContext } from './index.js'; const { jest } = import.meta; const provider = new Provider('https://logto.test'); +const tenantContext = new MockTenant(provider); + const mockAccessToken = { accountId: 'fooUser', clientId: 'fooClient', @@ -70,12 +74,19 @@ describe('koaOidcAuth middleware', () => { }, }; Sinon.stub(provider.AccessToken, 'find').resolves(mockAccessToken); - await koaOidcAuth(provider)(ctx, next); - expect(ctx.auth).toEqual({ type: 'user', id: 'fooUser', scopes: new Set(['openid']) }); + await koaOidcAuth(tenantContext)(ctx, next); + expect(ctx.auth).toEqual({ + type: 'user', + id: 'fooUser', + scopes: new Set(['openid']), + identityVerified: false, + }); }); it('expect to throw if authorization header is missing', async () => { - await expect(koaOidcAuth(provider)(ctx, next)).rejects.toMatchError(authHeaderMissingError); + await expect(koaOidcAuth(tenantContext)(ctx, next)).rejects.toMatchError( + authHeaderMissingError + ); }); it('expect to throw if authorization header token type not recognized ', async () => { @@ -86,7 +97,9 @@ describe('koaOidcAuth middleware', () => { }, }; - await expect(koaOidcAuth(provider)(ctx, next)).rejects.toMatchError(tokenNotSupportedError); + await expect(koaOidcAuth(tenantContext)(ctx, next)).rejects.toMatchError( + tokenNotSupportedError + ); }); it('expect to throw if access token is not found', async () => { @@ -98,7 +111,7 @@ describe('koaOidcAuth middleware', () => { }; Sinon.stub(provider.AccessToken, 'find').resolves(); - await expect(koaOidcAuth(provider)(ctx, next)).rejects.toMatchError(unauthorizedError); + await expect(koaOidcAuth(tenantContext)(ctx, next)).rejects.toMatchError(unauthorizedError); }); it('expect to throw if sub is missing', async () => { @@ -113,7 +126,7 @@ describe('koaOidcAuth middleware', () => { accountId: undefined, }); - await expect(koaOidcAuth(provider)(ctx, next)).rejects.toMatchError(unauthorizedError); + await expect(koaOidcAuth(tenantContext)(ctx, next)).rejects.toMatchError(unauthorizedError); }); it('expect to throw if access token does not have openid scope', async () => { @@ -128,6 +141,6 @@ describe('koaOidcAuth middleware', () => { scopes: new Set(['foo']), }); - await expect(koaOidcAuth(provider)(ctx, next)).rejects.toMatchError(forbiddenError); + await expect(koaOidcAuth(tenantContext)(ctx, next)).rejects.toMatchError(forbiddenError); }); }); diff --git a/packages/core/src/middleware/koa-auth/koa-oidc-auth.ts b/packages/core/src/middleware/koa-auth/koa-oidc-auth.ts index fdfadc4e5..5029bf5f4 100644 --- a/packages/core/src/middleware/koa-auth/koa-oidc-auth.ts +++ b/packages/core/src/middleware/koa-auth/koa-oidc-auth.ts @@ -1,18 +1,58 @@ import type { MiddlewareType } from 'koa'; import type { IRouterParamContext } from 'koa-router'; -import type Provider from 'oidc-provider'; import RequestError from '#src/errors/RequestError/index.js'; +import { + verificationRecordDataGuard, + buildVerificationRecord, +} from '#src/routes/experience/classes/verifications/index.js'; +import type Libraries from '#src/tenants/Libraries.js'; +import type Queries from '#src/tenants/Queries.js'; +import type TenantContext from '#src/tenants/TenantContext.js'; import assertThat from '#src/utils/assert-that.js'; +import { verificationRecordIdHeader } from './constants.js'; import { type WithAuthContext } from './types.js'; import { extractBearerTokenFromHeaders } from './utils.js'; +/** + * Builds a verification record by its id. + * The `userId` is optional and is only used for user sensitive permission verifications. + */ +const getVerificationRecordResultById = async ({ + id, + queries, + libraries, + userId, +}: { + id: string; + queries: Queries; + libraries: Libraries; + userId: string; +}): Promise => { + const record = await queries.verificationRecords.findActiveVerificationRecordById(id); + if (record?.userId !== userId) { + return false; + } + + const result = verificationRecordDataGuard.safeParse({ + ...record.data, + id: record.id, + }); + + if (!result.success) { + return false; + } + + const instance = buildVerificationRecord(libraries, queries, result.data); + return instance.isVerified; +}; + /** * Auth middleware for OIDC opaque token */ export default function koaOidcAuth( - provider: Provider + tenant: TenantContext ): MiddlewareType, ResponseBodyT> { const authMiddleware: MiddlewareType, ResponseBodyT> = async ( ctx, @@ -20,7 +60,7 @@ export default function koaOidcAuth { const { request } = ctx; const accessTokenValue = extractBearerTokenFromHeaders(request.headers); - const accessToken = await provider.AccessToken.find(accessTokenValue); + const accessToken = await tenant.provider.AccessToken.find(accessTokenValue); assertThat(accessToken, new RequestError({ code: 'auth.unauthorized', status: 401 })); @@ -28,10 +68,22 @@ export default function koaOidcAuth; + /** If the request is verified by a verification record, this will be set to `true`. */ + identityVerified?: boolean; }; export type WithAuthContext = diff --git a/packages/core/src/routes/init.ts b/packages/core/src/routes/init.ts index 2ec66ad3f..96a6879e8 100644 --- a/packages/core/src/routes/init.ts +++ b/packages/core/src/routes/init.ts @@ -104,7 +104,7 @@ const createRouters = (tenant: TenantContext) => { const anonymousRouter: AnonymousRouter = new Router(); const userRouter: UserRouter = new Router(); - userRouter.use(koaOidcAuth(tenant.provider)); + userRouter.use(koaOidcAuth(tenant)); // TODO(LOG-10147): Rename to koaApiHooks, this middleware is used for both management API and user API userRouter.use(koaManagementApiHooks(tenant.libraries.hooks)); profileRoutes(userRouter, tenant); diff --git a/packages/core/src/routes/profile/index.openapi.json b/packages/core/src/routes/profile/index.openapi.json index d91895d8e..f0849d742 100644 --- a/packages/core/src/routes/profile/index.openapi.json +++ b/packages/core/src/routes/profile/index.openapi.json @@ -118,7 +118,7 @@ "post": { "operationId": "UpdatePassword", "summary": "Update password", - "description": "Update password for the user, a verification record is required for checking sensitive permissions.", + "description": "Update password for the user, a logto-verification-id in header is required for checking sensitive permissions.", "requestBody": { "content": { "application/json": { @@ -126,9 +126,6 @@ "properties": { "password": { "description": "The new password for the user." - }, - "verificationRecordId": { - "description": "The verification record ID for checking sensitive permissions." } } } @@ -149,7 +146,7 @@ "post": { "operationId": "UpdatePrimaryEmail", "summary": "Update primary email", - "description": "Update primary email for the user, a verification record is required for checking sensitive permissions, and a new identifier verification record is required for the new email ownership verification.", + "description": "Update primary email for the user, a logto-verification-id in header is required for checking sensitive permissions, and a new identifier verification record is required for the new email ownership verification.", "requestBody": { "content": { "application/json": { @@ -158,9 +155,6 @@ "email": { "description": "The new email for the user." }, - "verificationRecordId": { - "description": "The verification record ID for checking sensitive permissions." - }, "newIdentifierVerificationRecordId": { "description": "The identifier verification record ID for the new email ownership verification." } @@ -186,7 +180,7 @@ "post": { "operationId": "UpdatePrimaryPhone", "summary": "Update primary phone", - "description": "Update primary phone for the user, a verification record is required for checking sensitive permissions, and a new identifier verification record is required for the new phone ownership verification.", + "description": "Update primary phone for the user, a logto-verification-id in header is required for checking sensitive permissions, and a new identifier verification record is required for the new phone ownership verification.", "requestBody": { "content": { "application/json": { @@ -195,9 +189,6 @@ "phone": { "description": "The new phone for the user." }, - "verificationRecordId": { - "description": "The verification record ID for checking sensitive permissions." - }, "newIdentifierVerificationRecordId": { "description": "The identifier verification record ID for the new phone ownership verification." } @@ -223,15 +214,12 @@ "post": { "operationId": "AddUserIdentities", "summary": "Add a user identity", - "description": "Add an identity (social identity) to the user, a verification record is required for checking sensitive permissions, and a verification record for the social identity is required.", + "description": "Add an identity (social identity) to the user, a logto-verification-id in header is required for checking sensitive permissions, and a verification record for the social identity is required.", "requestBody": { "content": { "application/json": { "schema": { "properties": { - "verificationRecordId": { - "description": "The verification record ID for checking sensitive permissions." - }, "newIdentifierVerificationRecordId": { "description": "The identifier verification record ID for the new social identity ownership verification." } @@ -251,14 +239,7 @@ "delete": { "operationId": "DeleteIdentity", "summary": "Delete a user identity", - "description": "Delete an identity (social identity) from the user, a verification record is required for checking sensitive permissions.", - "parameters": [ - { - "name": "verificationRecordId", - "in": "query", - "description": "The verification record ID for checking sensitive permissions." - } - ], + "description": "Delete an identity (social identity) from the user, a logto-verification-id in header is required for checking sensitive permissions.", "responses": { "204": { "description": "The identity was deleted successfully." diff --git a/packages/core/src/routes/profile/index.ts b/packages/core/src/routes/profile/index.ts index c0e0cc1c0..ad99d45db 100644 --- a/packages/core/src/routes/profile/index.ts +++ b/packages/core/src/routes/profile/index.ts @@ -13,10 +13,7 @@ import koaGuard from '#src/middleware/koa-guard.js'; import { EnvSet } from '../../env-set/index.js'; import RequestError from '../../errors/RequestError/index.js'; import { encryptUserPassword } from '../../libraries/user.utils.js'; -import { - buildVerificationRecordByIdAndType, - verifyUserSensitivePermission, -} from '../../libraries/verification.js'; +import { buildVerificationRecordByIdAndType } from '../../libraries/verification.js'; import assertThat from '../../utils/assert-that.js'; import { PasswordValidator } from '../experience/classes/libraries/password-validator.js'; import type { UserRouter, RouterInitArgs } from '../types.js'; @@ -144,12 +141,16 @@ export default function profileRoutes( router.post( '/profile/password', koaGuard({ - body: z.object({ password: z.string().min(1), verificationRecordId: z.string() }), + body: z.object({ password: z.string().min(1) }), status: [204, 400, 401, 422], }), async (ctx, next) => { - const { id: userId } = ctx.auth; - const { password, verificationRecordId } = ctx.guard.body; + const { id: userId, identityVerified } = ctx.auth; + assertThat( + identityVerified, + new RequestError({ code: 'verification_record.permission_denied', status: 401 }) + ); + const { password } = ctx.guard.body; const { fields } = ctx.accountCenter; assertThat( fields.password === AccountCenterControlValue.Edit, @@ -161,13 +162,6 @@ export default function profileRoutes( const passwordPolicyChecker = new PasswordValidator(signInExperience.passwordPolicy, user); await passwordPolicyChecker.validatePassword(password, user); - await verifyUserSensitivePermission({ - userId, - id: verificationRecordId, - queries, - libraries, - }); - const { passwordEncrypted, passwordEncryptionMethod } = await encryptUserPassword(password); const updatedUser = await updateUserById(userId, { passwordEncrypted, @@ -187,14 +181,17 @@ export default function profileRoutes( koaGuard({ body: z.object({ email: z.string().regex(emailRegEx), - verificationRecordId: z.string(), newIdentifierVerificationRecordId: z.string(), }), status: [204, 400, 401], }), async (ctx, next) => { - const { id: userId, scopes } = ctx.auth; - const { email, verificationRecordId, newIdentifierVerificationRecordId } = ctx.guard.body; + const { id: userId, scopes, identityVerified } = ctx.auth; + assertThat( + identityVerified, + new RequestError({ code: 'verification_record.permission_denied', status: 401 }) + ); + const { email, newIdentifierVerificationRecordId } = ctx.guard.body; const { fields } = ctx.accountCenter; assertThat( fields.email === AccountCenterControlValue.Edit, @@ -203,13 +200,6 @@ export default function profileRoutes( assertThat(scopes.has(UserScope.Email), 'auth.unauthorized'); - await verifyUserSensitivePermission({ - userId, - id: verificationRecordId, - queries, - libraries, - }); - // Check new identifier const newVerificationRecord = await buildVerificationRecordByIdAndType({ type: VerificationType.EmailVerificationCode, @@ -237,14 +227,17 @@ export default function profileRoutes( koaGuard({ body: z.object({ phone: z.string().regex(phoneRegEx), - verificationRecordId: z.string(), newIdentifierVerificationRecordId: z.string(), }), status: [204, 400, 401], }), async (ctx, next) => { - const { id: userId, scopes } = ctx.auth; - const { phone, verificationRecordId, newIdentifierVerificationRecordId } = ctx.guard.body; + const { id: userId, scopes, identityVerified } = ctx.auth; + assertThat( + identityVerified, + new RequestError({ code: 'verification_record.permission_denied', status: 401 }) + ); + const { phone, newIdentifierVerificationRecordId } = ctx.guard.body; const { fields } = ctx.accountCenter; assertThat( fields.phone === AccountCenterControlValue.Edit, @@ -253,13 +246,6 @@ export default function profileRoutes( assertThat(scopes.has(UserScope.Phone), 'auth.unauthorized'); - await verifyUserSensitivePermission({ - userId, - id: verificationRecordId, - queries, - libraries, - }); - // Check new identifier const newVerificationRecord = await buildVerificationRecordByIdAndType({ type: VerificationType.PhoneVerificationCode, @@ -286,14 +272,17 @@ export default function profileRoutes( '/profile/identities', koaGuard({ body: z.object({ - verificationRecordId: z.string(), newIdentifierVerificationRecordId: z.string(), }), status: [204, 400, 401], }), async (ctx, next) => { - const { id: userId, scopes } = ctx.auth; - const { verificationRecordId, newIdentifierVerificationRecordId } = ctx.guard.body; + const { id: userId, scopes, identityVerified } = ctx.auth; + assertThat( + identityVerified, + new RequestError({ code: 'verification_record.permission_denied', status: 401 }) + ); + const { newIdentifierVerificationRecordId } = ctx.guard.body; const { fields } = ctx.accountCenter; assertThat( fields.social === AccountCenterControlValue.Edit, @@ -302,13 +291,6 @@ export default function profileRoutes( assertThat(scopes.has(UserScope.Identities), 'auth.unauthorized'); - await verifyUserSensitivePermission({ - userId, - id: verificationRecordId, - queries, - libraries, - }); - // Check new identifier const newVerificationRecord = await buildVerificationRecordByIdAndType({ type: VerificationType.Social, @@ -350,15 +332,14 @@ export default function profileRoutes( '/profile/identities/:target', koaGuard({ params: z.object({ target: z.string() }), - query: z.object({ - // TODO: Move all sensitive permission checks to the header - verificationRecordId: z.string(), - }), status: [204, 400, 401, 404], }), async (ctx, next) => { - const { id: userId, scopes } = ctx.auth; - const { verificationRecordId } = ctx.guard.query; + const { id: userId, scopes, identityVerified } = ctx.auth; + assertThat( + identityVerified, + new RequestError({ code: 'verification_record.permission_denied', status: 401 }) + ); const { target } = ctx.guard.params; const { fields } = ctx.accountCenter; assertThat( @@ -368,13 +349,6 @@ export default function profileRoutes( assertThat(scopes.has(UserScope.Identities), 'auth.unauthorized'); - await verifyUserSensitivePermission({ - userId, - id: verificationRecordId, - queries, - libraries, - }); - const user = await findUserById(userId); assertThat( diff --git a/packages/integration-tests/src/api/profile.ts b/packages/integration-tests/src/api/profile.ts index 3bbf2276b..cf6ccec67 100644 --- a/packages/integration-tests/src/api/profile.ts +++ b/packages/integration-tests/src/api/profile.ts @@ -1,11 +1,17 @@ import { type UserProfileResponse } from '@logto/schemas'; import { type KyInstance } from 'ky'; +const verificationRecordIdHeader = 'logto-verification-id'; + export const updatePassword = async ( api: KyInstance, verificationRecordId: string, password: string -) => api.post('api/profile/password', { json: { password, verificationRecordId } }); +) => + api.post('api/profile/password', { + json: { password }, + headers: { [verificationRecordIdHeader]: verificationRecordId }, + }); export const updatePrimaryEmail = async ( api: KyInstance, @@ -14,7 +20,8 @@ export const updatePrimaryEmail = async ( newIdentifierVerificationRecordId: string ) => api.post('api/profile/primary-email', { - json: { email, verificationRecordId, newIdentifierVerificationRecordId }, + json: { email, newIdentifierVerificationRecordId }, + headers: { [verificationRecordIdHeader]: verificationRecordId }, }); export const updatePrimaryPhone = async ( @@ -24,7 +31,8 @@ export const updatePrimaryPhone = async ( newIdentifierVerificationRecordId: string ) => api.post('api/profile/primary-phone', { - json: { phone, verificationRecordId, newIdentifierVerificationRecordId }, + json: { phone, newIdentifierVerificationRecordId }, + headers: { [verificationRecordIdHeader]: verificationRecordId }, }); export const updateIdentities = async ( @@ -33,7 +41,8 @@ export const updateIdentities = async ( newIdentifierVerificationRecordId: string ) => api.post('api/profile/identities', { - json: { verificationRecordId, newIdentifierVerificationRecordId }, + json: { newIdentifierVerificationRecordId }, + headers: { [verificationRecordIdHeader]: verificationRecordId }, }); export const deleteIdentity = async ( @@ -42,7 +51,7 @@ export const deleteIdentity = async ( verificationRecordId: string ) => api.delete(`api/profile/identities/${target}`, { - searchParams: { verificationRecordId }, + headers: { [verificationRecordIdHeader]: verificationRecordId }, }); export const updateUser = async (api: KyInstance, body: Record) => diff --git a/packages/integration-tests/src/tests/api/profile/account-center-reject.test.ts b/packages/integration-tests/src/tests/api/profile/account-center-reject.test.ts index 5df9d5e2d..31aa24df1 100644 --- a/packages/integration-tests/src/tests/api/profile/account-center-reject.test.ts +++ b/packages/integration-tests/src/tests/api/profile/account-center-reject.test.ts @@ -13,12 +13,14 @@ import { updatePrimaryPhone, updateUser, } from '#src/api/profile.js'; +import { createVerificationRecordByPassword } from '#src/api/verification-record.js'; import { expectRejects } from '#src/helpers/index.js'; import { createDefaultTenantUserWithPassword, deleteDefaultTenantUser, signInAndGetUserApi, } from '#src/helpers/profile.js'; +import { enableAllPasswordSignInMethods } from '#src/helpers/sign-in-experience.js'; import { devFeatureTest, generateEmail, generatePhone } from '#src/utils.js'; const { describe, it } = devFeatureTest; @@ -30,6 +32,7 @@ const expectedError = { describe('profile, account center fields disabled', () => { beforeAll(async () => { + await enableAllPasswordSignInMethods(); await updateAccountCenter({ enabled: true, fields: { @@ -79,38 +82,29 @@ describe('profile, account center fields disabled', () => { status: 400, }); - await expectRejects(updatePassword(api, 'verification-record-id', 'new-password'), { + const verificationRecordId = await createVerificationRecordByPassword(api, password); + await expectRejects(updatePassword(api, verificationRecordId, 'new-password'), { code: 'account_center.filed_not_editable', status: 400, }); await expectRejects( - updatePrimaryEmail( - api, - generateEmail(), - 'verification-record-id', - 'new-verification-record-id' - ), + updatePrimaryEmail(api, generateEmail(), verificationRecordId, 'new-verification-record-id'), expectedError ); await expectRejects( - updatePrimaryPhone( - api, - generatePhone(), - 'verification-record-id', - 'new-verification-record-id' - ), + updatePrimaryPhone(api, generatePhone(), verificationRecordId, 'new-verification-record-id'), expectedError ); await expectRejects( - updateIdentities(api, 'verification-record-id', 'new-verification-record-id'), + updateIdentities(api, verificationRecordId, 'new-verification-record-id'), expectedError ); await expectRejects( - deleteIdentity(api, mockSocialConnectorTarget, 'verification-record-id'), + deleteIdentity(api, mockSocialConnectorTarget, verificationRecordId), expectedError ); diff --git a/packages/integration-tests/src/tests/api/profile/email-and-phone.test.ts b/packages/integration-tests/src/tests/api/profile/email-and-phone.test.ts index b21a371b9..619197cdf 100644 --- a/packages/integration-tests/src/tests/api/profile/email-and-phone.test.ts +++ b/packages/integration-tests/src/tests/api/profile/email-and-phone.test.ts @@ -33,14 +33,10 @@ describe('profile (email and phone)', () => { const { user, username, password } = await createDefaultTenantUserWithPassword(); const api = await signInAndGetUserApi(username, password); const newEmail = generateEmail(); + const verificationRecordId = await createVerificationRecordByPassword(api, password); await expectRejects( - updatePrimaryEmail( - api, - newEmail, - 'invalid-verification-record-id', - 'new-verification-record-id' - ), + updatePrimaryEmail(api, newEmail, verificationRecordId, 'new-verification-record-id'), { code: 'auth.unauthorized', status: 400, @@ -144,14 +140,10 @@ describe('profile (email and phone)', () => { const { user, username, password } = await createDefaultTenantUserWithPassword(); const api = await signInAndGetUserApi(username, password); const newPhone = generatePhone(); + const verificationRecordId = await createVerificationRecordByPassword(api, password); await expectRejects( - updatePrimaryPhone( - api, - newPhone, - 'invalid-verification-record-id', - 'new-verification-record-id' - ), + updatePrimaryPhone(api, newPhone, verificationRecordId, 'new-verification-record-id'), { code: 'auth.unauthorized', status: 400, diff --git a/packages/integration-tests/src/tests/api/profile/index.test.ts b/packages/integration-tests/src/tests/api/profile/index.test.ts index e160711e2..766e45269 100644 --- a/packages/integration-tests/src/tests/api/profile/index.test.ts +++ b/packages/integration-tests/src/tests/api/profile/index.test.ts @@ -254,8 +254,9 @@ describe('profile', () => { const { user, username, password } = await createDefaultTenantUserWithPassword(); const api = await signInAndGetUserApi(username, password); const newPassword = '123456'; + const verificationRecordId = await createVerificationRecordByPassword(api, password); - await expectRejects(updatePassword(api, 'invalid-varification-record-id', newPassword), { + await expectRejects(updatePassword(api, verificationRecordId, newPassword), { code: 'password.rejected', status: 422, }); diff --git a/packages/integration-tests/src/tests/api/profile/social.test.ts b/packages/integration-tests/src/tests/api/profile/social.test.ts index 5b55bd20f..2e90df665 100644 --- a/packages/integration-tests/src/tests/api/profile/social.test.ts +++ b/packages/integration-tests/src/tests/api/profile/social.test.ts @@ -54,9 +54,10 @@ describe('profile (social)', () => { it('should fail if scope is missing', async () => { const { user, username, password } = await createDefaultTenantUserWithPassword(); const api = await signInAndGetUserApi(username, password); + const verificationRecordId = await createVerificationRecordByPassword(api, password); await expectRejects( - updateIdentities(api, 'invalid-verification-record-id', 'new-verification-record-id'), + updateIdentities(api, verificationRecordId, 'new-verification-record-id'), { code: 'auth.unauthorized', status: 400, @@ -107,7 +108,6 @@ describe('profile (social)', () => { const api = await signInAndGetUserApi(username, password, { scopes: [UserScope.Profile, UserScope.Identities], }); - await expectRejects( createSocialVerificationRecord(api, 'invalid-connector-id', state, redirectUri), { @@ -173,14 +173,12 @@ describe('profile (social)', () => { it('should fail if scope is missing', async () => { const { user, username, password } = await createDefaultTenantUserWithPassword(); const api = await signInAndGetUserApi(username, password); + const verificationRecordId = await createVerificationRecordByPassword(api, password); - await expectRejects( - deleteIdentity(api, mockSocialConnectorTarget, 'invalid-verification-record-id'), - { - code: 'auth.unauthorized', - status: 400, - } - ); + await expectRejects(deleteIdentity(api, mockSocialConnectorTarget, verificationRecordId), { + code: 'auth.unauthorized', + status: 400, + }); await deleteDefaultTenantUser(user.id); });