setModuleConfig('reCAPTCHA', 'enabled', 'false'); $user = api_fixtures()->createUser([ 'display_name' => 'API Login User', 'password_plaintext' => 'Secret123!', ]); $response = api_client()->post('/auth/login', [ 'customer_number' => $user['customer_number'], 'password' => $user['password_plaintext'], ]); $response ->assertStatus(200) ->assertEnvelope() ->assertSuccess(); expect($response->data()) ->toBeArray() ->toHaveKey('token') ->and($response->data()['token']) ->toBeString() ->toHaveLength(64); }); it('rejects invalid login payloads and credentials', function (): void { api_test_covers('POST /auth/login', 'failure'); api_fixtures()->setModuleConfig('reCAPTCHA', 'enabled', 'false'); $user = api_fixtures()->createUser([ 'password_plaintext' => 'Secret123!', ]); $missingPassword = api_client()->post('/auth/login', [ 'customer_number' => $user['customer_number'], ]); $missingPassword ->assertStatus(400) ->assertEnvelope() ->assertSuccess(false) ->assertMessage('Missing required parameters: password'); $invalidCredentials = api_client()->post('/auth/login', [ 'customer_number' => $user['customer_number'], 'password' => 'wrong-password', ]); $invalidCredentials ->assertStatus(401) ->assertEnvelope() ->assertSuccess(false) ->assertMessage('Invalid credentials'); }); it('returns the cached auth session payload for a valid token', function (): void { api_test_covers('GET /auth/session', 'happy'); $session = api_fixtures()->createUserSession(['list_departments'], [ 'display_name' => 'Session User', ]); api_fixtures()->cacheAuthSessionForUser( $session['user'], $session['token'], ['list_departments'], [ 'two_factor_enabled' => false, ] ); api_fixtures()->setModuleConfig('economic', 'transactionDraftCustomerNumber', '445566', 'int'); $response = api_client()->get('/auth/session', $session['headers']); $response ->assertStatus(200) ->assertEnvelope() ->assertSuccess(); expect($response->data()) ->toBeArray() ->toHaveKey('customer_number', $session['user']['customer_number']) ->toHaveKey('two_factor_enabled', false) ->and($response->data()['permissions']) ->toContain('list_departments') ->and($response->data()['runtime_config']['economic']['transaction_draft_customer_number'] ?? null) ->toBe(445566); }); it('includes economic runtime config for uncached auth sessions', function (): void { api_test_covers('GET /auth/session', 'happy'); api_fixtures()->setModuleConfig('economic', 'transactionDraftCustomerNumber', '556677', 'int'); $session = api_fixtures()->createUserSession(['list_departments'], [ 'display_name' => 'Fresh Session User', ]); $response = api_client()->get('/auth/session', $session['headers']); $response ->assertStatus(200) ->assertEnvelope() ->assertSuccess(); expect($response->data()) ->toBeArray() ->toHaveKey('customer_number', $session['user']['customer_number']) ->and($response->data()['runtime_config']['economic']['transaction_draft_customer_number'] ?? null) ->toBe(556677); }); it('rejects invalid auth session tokens', function (): void { api_test_covers('GET /auth/session', 'auth'); $response = api_client()->get('/auth/session', [ 'Authorization' => 'Bearer invalid-token', ]); $response ->assertStatus(500) ->assertEnvelope() ->assertSuccess(false) ->assertMessageContains('Token not found'); }); it('logs out and invalidates the token for future session calls', function (): void { api_test_covers('GET /auth/logout', 'happy'); $session = api_fixtures()->createUserSession(['list_departments'], [ 'display_name' => 'Logout User', ]); api_fixtures()->cacheAuthSessionForUser( $session['user'], $session['token'], ['list_departments'] ); $logoutResponse = api_client()->get('/auth/logout', $session['headers']); $logoutResponse ->assertStatus(200) ->assertEnvelope() ->assertSuccess() ->assertMessage('Logged out'); $followUpSession = api_client()->get('/auth/session', $session['headers']); $followUpSession ->assertStatus(500) ->assertEnvelope() ->assertSuccess(false) ->assertMessageContains('Token not found'); }); it('logs out and invalidates cached subuser sessions', function (): void { api_test_covers('GET /auth/logout', 'happy'); $user = api_fixtures()->createUser(); $session = api_fixtures()->createSubuserSession((int)$user['customer_number'], [], [ 'username' => 'logout-driver', ]); $warmCache = api_client()->get('/subusers/me', $session['headers']); $warmCache ->assertStatus(200) ->assertEnvelope() ->assertSuccess(); $logoutResponse = api_client()->get('/auth/logout', $session['headers']); $logoutResponse ->assertStatus(200) ->assertEnvelope() ->assertSuccess() ->assertMessage('Logged out'); $followUpProfile = api_client()->get('/subusers/me', $session['headers']); $followUpProfile ->assertStatus(401) ->assertEnvelope() ->assertSuccess(false) ->assertMessage('Unauthorized'); }); it('rejects invalid logout tokens', function (): void { api_test_covers('GET /auth/logout', 'auth'); $response = api_client()->get('/auth/logout', [ 'Authorization' => 'Bearer invalid-token', ]); $response ->assertStatus(500) ->assertEnvelope() ->assertSuccess(false) ->assertMessageContains('Token not found'); });