import { AuthenticationClient } from "clients/authentication" ; import { ManagementClient } from "clients/management" ; import { chance , request } from "_/helpers" ; import { mockAuthenticateRequestWithCredentials , mockAuthenticateRequestWithToken , mockRegisterRequest } from "_/mocks/common" ; describe ( "POST /authenticate" , ( ) => { const auth = new AuthenticationClient ( ) ; const mgmt = new ManagementClient ( ) ; it ( "should return error for empty request" , ( ) => { return request . post ( "/authenticate" ) . set ( "Content-Type" , "application/json" ) . expect ( 400 , { type : "TypeError" , message : "Invalid request" } ) ; } ) ; it ( "should return error for malformed request" , ( ) => { return request . post ( "/authenticate" ) . set ( "Content-Type" , "application/json" ) . send ( `/${ chance . string ( ) }` ) . expect ( 400 , { type : "TypeError" , message : "Invalid request" } ) ; } ) ; it ( "should return error for invalid request" , ( ) => { return request . post ( "/authenticate" ) . set ( "Content-Type" , "application/json" ) . send ( `{}` ) . expect ( 400 , { type : "TypeError" , message : "Invalid request" } ) ; } ) ; it ( "should return error for non-existent user" , ( ) => { return request . post ( "/authenticate" ) . set ( "Content-Type" , "application/json" ) . send ( mockAuthenticateRequestWithCredentials ( ) ) . expect ( 400 , { type : "NotAuthorizedException" , message : "Incorrect username or password" } ) ; } ) ; it ( "should return error for invalid refresh token" , ( ) => { return request . post ( "/authenticate" ) . set ( "Content-Type" , "application/json" ) . send ( mockAuthenticateRequestWithToken ( ) ) . expect ( 400 , { type : "NotAuthorizedException" , message : "Invalid Refresh Token" } ) ; } ) ; describe ( "with unconfirmed user" , ( ) => { const { email , password } = mockRegisterRequest ( ) ; let id ; beforeAll ( async ( ) => { const { subject } = await auth . register ( email , password ) ; id = subject ; } ) ; afterAll ( async ( ) => { await mgmt . deleteUser ( id ) ; } ) ; it ( "should return error for valid credentials" , async ( ) => { return request . post ( "/authenticate" ) . set ( "Content-Type" , "application/json" ) . send ( { username : email , password } ) . expect ( 400 , { type : "NotAuthorizedException" , message : "Incorrect username or password" } ) ; } ) ; } ) ; describe ( "with confirmed user" , ( ) => { const { email , password } = mockRegisterRequest ( ) ; beforeAll ( async ( ) => { const { subject } = await auth . register ( email , password ) ; await mgmt . verifyUser ( subject ) ; } ) ; afterAll ( async ( ) => { await mgmt . deleteUser ( email ) ; } ) ; it ( "should return identity token for valid credentials" , async ( ) => { const { body } = await request . post ( "/authenticate" ) . set ( "Content-Type" , "application/json" ) . send ( { username : email , password } ) . expect ( 200 ) ; expect ( body . id . token ) . toMatch ( /^([a-zA-Z0-9\-_]+\.){2}[a-zA-Z0-9\-_]+$/ ) ; expect ( Date . parse ( body . id . expires ) ) . toBeGreaterThan ( Date . now ( ) + 1000 * 59 * 60 ) ; } ) ; it ( "should return access token for valid credentials" , async ( ) => { const { body } = await request . post ( "/authenticate" ) . set ( "Content-Type" , "application/json" ) . send ( { username : email , password } ) . expect ( 200 ) ; expect ( body . access . token ) . toMatch ( /^([a-zA-Z0-9\-_]+\.){2}[a-zA-Z0-9\-_]+$/ ) ; expect ( Date . parse ( body . access . expires ) ) . toBeGreaterThan ( Date . now ( ) + 1000 * 59 * 60 ) ; } ) ; it ( "should return refresh token for valid credentials (body)" , async ( ) => { const { body } = await request . post ( "/authenticate" ) . set ( "Content-Type" , "application/json" ) . send ( { username : email , password , remember : true } ) . expect ( 200 ) ; expect ( body . refresh . token ) . toMatch ( /^([a-zA-Z0-9\-_]+\.){4}[a-zA-Z0-9\-_]+$/ ) ; expect ( Date . parse ( body . refresh . expires ) ) . toBeGreaterThan ( Date . now ( ) + 1000 * 59 * 60 * 24 * 30 ) ; } ) ; it ( "should return refresh token for valid credentials (cookie)" , async ( ) => { const { body , header } = await request . post ( "/authenticate" ) . set ( "Content-Type" , "application/json" ) . send ( { username : email , password , remember : true } ) . expect ( 200 ) ; expect ( header [ "set-cookie" ] ) . toMatch ( `__Secure-token=${ encodeURIComponent ( body . refresh . token ) }; Domain=${ process . env . COGNITO_IDENTITY_POOL_PROVIDER ! }; Path=/${ process . env . API_BASE_PATH ! }/authenticate; Expires=${ new Date ( Date . parse ( body . refresh . expires ) ) . toUTCString ( ) }; HttpOnly; Secure; SameSite=Strict` ) ; } ) ; it ( "should return identity token for valid refresh token" , async ( ) => { const { body : { refresh } } = await request . post ( "/authenticate" ) . set ( "Content-Type" , "application/json" ) . send ( { username : email , password , remember : true } ) . expect ( 200 ) ; const { body } = await request . post ( "/authenticate" ) . send ( { token : refresh . token } ) . expect ( 200 ) ; expect ( body . id . token ) . toMatch ( /^([a-zA-Z0-9\-_]+\.){2}[a-zA-Z0-9\-_]+$/ ) ; expect ( Date . parse ( body . id . expires ) ) . toBeGreaterThanOrEqual ( Date . now ( ) + 1000 * 59 * 60 ) ; } ) ; it ( "should return access token for valid refresh token" , async ( ) => { const { body : { refresh } } = await request . post ( "/authenticate" ) . set ( "Content-Type" , "application/json" ) . send ( { username : email , password , remember : true } ) . expect ( 200 ) ; const { body } = await request . post ( "/authenticate" ) . send ( { token : refresh . token } ) . expect ( 200 ) ; expect ( body . access . token ) . toMatch ( /^([a-zA-Z0-9\-_]+\.){2}[a-zA-Z0-9\-_]+$/ ) ; expect ( Date . parse ( body . access . expires ) ) . toBeGreaterThanOrEqual ( Date . now ( ) + 1000 * 59 * 60 ) ; } ) ; it ( "should return error for invalid credentials" , ( ) => { return request . post ( "/authenticate" ) . set ( "Content-Type" , "application/json" ) . send ( { username : email , password : chance . string ( ) } ) . expect ( 400 , { type : "NotAuthorizedException" , message : "Incorrect username or password" } ) ; } ) ; } ) ; } ) ;