/** * Cognito Identity Provider integration tests. */ import { describe, it, expect, beforeAll, afterAll } from 'vitest'; import { CognitoIdentityProviderClient, CreateUserPoolCommand, CreateUserPoolClientCommand, ExplicitAuthFlowsType, AdminCreateUserCommand, AdminSetUserPasswordCommand, InitiateAuthCommand, AdminGetUserCommand, ListUsersCommand, DeleteUserPoolCommand, SignUpCommand, ConfirmSignUpCommand, CreateGroupCommand, GetGroupCommand, ListGroupsCommand, DeleteGroupCommand, AdminAddUserToGroupCommand, AdminRemoveUserFromGroupCommand, AdminListGroupsForUserCommand, SetUserPoolMfaConfigCommand, GetUserPoolMfaConfigCommand, } from '@aws-sdk/client-cognito-identity-provider'; import { makeClient, uniqueName, ENDPOINT, fetchLatestSesVerificationCode } from './setup'; describe('Cognito', () => { let cognito: CognitoIdentityProviderClient; let poolId: string; let clientId: string; beforeAll(() => { cognito = makeClient(CognitoIdentityProviderClient); }); afterAll(async () => { try { if (poolId) { await cognito.send(new DeleteUserPoolCommand({ UserPoolId: poolId })); } } catch { // ignore } }); it('should create user pool', async () => { const response = await cognito.send( new CreateUserPoolCommand({ PoolName: `test-pool-${uniqueName()}`, AutoVerifiedAttributes: ['email'], }) ); poolId = response.UserPool!.Id!; expect(poolId).toBeTruthy(); }); it('should create user pool client', async () => { const response = await cognito.send( new CreateUserPoolClientCommand({ UserPoolId: poolId, ClientName: `test-client-${uniqueName()}`, ExplicitAuthFlows: [ExplicitAuthFlowsType.ALLOW_USER_PASSWORD_AUTH], }) ); clientId = response.UserPoolClient!.ClientId!; expect(clientId).toBeTruthy(); }); it('should admin create user', async () => { const response = await cognito.send( new AdminCreateUserCommand({ UserPoolId: poolId, Username: 'testuser', TemporaryPassword: 'Temp123!', UserAttributes: [{ Name: 'email', Value: 'testuser@example.com' }], }) ); expect(response.User?.Username).toBe('testuser'); }); it('should admin set user password', async () => { await cognito.send( new AdminSetUserPasswordCommand({ UserPoolId: poolId, Username: 'testuser', Password: 'Perm456!', Permanent: true, }) ); }); it('should admin get user', async () => { const response = await cognito.send( new AdminGetUserCommand({ UserPoolId: poolId, Username: 'testuser' }) ); expect(response.UserStatus).toBe('CONFIRMED'); }); it('should list users', async () => { const response = await cognito.send(new ListUsersCommand({ UserPoolId: poolId })); expect(response.Users?.some((u) => u.Username === 'testuser')).toBe(true); }); it('should initiate auth USER_PASSWORD_AUTH', async () => { const response = await cognito.send( new InitiateAuthCommand({ AuthFlow: 'USER_PASSWORD_AUTH', AuthParameters: { USERNAME: 'testuser', PASSWORD: 'Perm456!' }, ClientId: clientId, }) ); expect(response.AuthenticationResult?.AccessToken).toBeTruthy(); expect(response.AuthenticationResult?.IdToken).toBeTruthy(); }); it('should sign up and confirm user', async () => { const email = 'testuser2@example.com'; await cognito.send( new SignUpCommand({ ClientId: clientId, Username: 'testuser2', Password: 'Pass789!', UserAttributes: [{ Name: 'email', Value: email }], }) ); const confirmationCode = await fetchLatestSesVerificationCode(email); await cognito.send( new ConfirmSignUpCommand({ ClientId: clientId, Username: 'testuser2', ConfirmationCode: confirmationCode, }) ); }); it('should create group', async () => { const response = await cognito.send( new CreateGroupCommand({ UserPoolId: poolId, GroupName: 'test-group', Description: 'Test group', Precedence: 1, }) ); expect(response.Group?.GroupName).toBe('test-group'); }); it('should get group', async () => { const response = await cognito.send( new GetGroupCommand({ UserPoolId: poolId, GroupName: 'test-group' }) ); expect(response.Group?.GroupName).toBe('test-group'); expect(response.Group?.Description).toBe('Test group'); expect(response.Group?.Precedence).toBe(1); }); it('should fail to create duplicate group', async () => { await expect( cognito.send( new CreateGroupCommand({ UserPoolId: poolId, GroupName: 'test-group' }) ) ).rejects.toThrow(); }); it('should list groups', async () => { const response = await cognito.send(new ListGroupsCommand({ UserPoolId: poolId })); expect(response.Groups?.some((g) => g.GroupName === 'test-group')).toBe(true); }); it('should add user to group', async () => { await cognito.send( new AdminAddUserToGroupCommand({ UserPoolId: poolId, GroupName: 'test-group', Username: 'testuser', }) ); }); it('should list groups for user', async () => { const response = await cognito.send( new AdminListGroupsForUserCommand({ UserPoolId: poolId, Username: 'testuser' }) ); expect(response.Groups?.some((g) => g.GroupName === 'test-group')).toBe(true); }); it('should return groups in JWT', async () => { const response = await cognito.send( new InitiateAuthCommand({ AuthFlow: 'USER_PASSWORD_AUTH', AuthParameters: { USERNAME: 'testuser', PASSWORD: 'Perm456!' }, ClientId: clientId, }) ); const token = response.AuthenticationResult?.AccessToken!; const parts = token.split('.'); const payload = JSON.parse(Buffer.from(parts[1], 'base64url').toString('utf8')); expect(Array.isArray(payload['cognito:groups'])).toBe(true); expect(payload['cognito:groups']?.includes('test-group')).toBe(true); }); it('should remove user from group', async () => { await cognito.send( new AdminRemoveUserFromGroupCommand({ UserPoolId: poolId, GroupName: 'test-group', Username: 'testuser', }) ); }); it('should verify user has no groups', async () => { const response = await cognito.send( new AdminListGroupsForUserCommand({ UserPoolId: poolId, Username: 'testuser' }) ); expect(response.Groups?.length).toBe(0); }); it('should delete group', async () => { await cognito.send( new DeleteGroupCommand({ UserPoolId: poolId, GroupName: 'test-group' }) ); }); it('should fail to get deleted group', async () => { await expect( cognito.send(new GetGroupCommand({ UserPoolId: poolId, GroupName: 'test-group' })) ).rejects.toThrow(); }); it('should access JWKS endpoint', async () => { const resp = await fetch(`${ENDPOINT}/${poolId}/.well-known/jwks.json`); expect(resp.ok).toBe(true); const json = await resp.json(); expect(Array.isArray(json.keys)).toBe(true); expect(json.keys.length).toBeGreaterThan(0); expect(json.keys[0].kty).toBe('RSA'); expect(json.keys[0].alg).toBe('RS256'); }); it('should delete user pool', async () => { await cognito.send(new DeleteUserPoolCommand({ UserPoolId: poolId })); poolId = ''; }); }); describe('Cognito MFA configuration', () => { let cognito: CognitoIdentityProviderClient; let poolId: string; beforeAll(async () => { cognito = makeClient(CognitoIdentityProviderClient); const pool = await cognito.send( new CreateUserPoolCommand({ PoolName: `mfa-${uniqueName()}` }) ); poolId = pool.UserPool!.Id!; }); afterAll(async () => { if (poolId) { await cognito .send(new DeleteUserPoolCommand({ UserPoolId: poolId })) .catch((error) => console.warn(`failed to delete MFA test pool ${poolId}`, error)); } }); it('should report OFF and omit software-token config before it is set', async () => { const config = await cognito.send(new GetUserPoolMfaConfigCommand({ UserPoolId: poolId })); expect(config.MfaConfiguration).toBe('OFF'); // The live service returns only the factors that have been configured. expect(config.SoftwareTokenMfaConfiguration).toBeUndefined(); }); it('should set and round-trip MFA configuration', async () => { const set = await cognito.send( new SetUserPoolMfaConfigCommand({ UserPoolId: poolId, MfaConfiguration: 'OPTIONAL', SoftwareTokenMfaConfiguration: { Enabled: true }, }) ); expect(set.MfaConfiguration).toBe('OPTIONAL'); expect(set.SoftwareTokenMfaConfiguration?.Enabled).toBe(true); // What the Terraform provider reads back to decide whether // mfa_configuration / software_token_mfa_configuration have drifted. const got = await cognito.send(new GetUserPoolMfaConfigCommand({ UserPoolId: poolId })); expect(got.MfaConfiguration).toBe('OPTIONAL'); expect(got.SoftwareTokenMfaConfiguration?.Enabled).toBe(true); }); it('should reject an invalid MfaConfiguration', async () => { await expect( cognito.send( new SetUserPoolMfaConfigCommand({ UserPoolId: poolId, MfaConfiguration: 'SOMETIMES' as never, }) ) ).rejects.toThrow(); }); });