Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .phpunit.cache/test-results

Large diffs are not rendered by default.

167 changes: 12 additions & 155 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,167 +2,24 @@

All notable changes to `laravel-bexio` will be documented in this file.

## [Unreleased]
## 20251110

### 🚨 Breaking Changes
### Removed ContactAdditionalAddresses

#### OAuth Implementation
- **Removed** `ContactAdditionalAddressDTO` and `CreateEditContactAdditionalAddressDTO`
- **Removed** all `ContactAdditionalAddresses` request classes:
- `CreateContactAdditionalAddressRequest`
- `EditAContactAdditionalAddressRequest`
- `FetchAContactAdditionalAddressRequest`
- `FetchAListOfContactAdditionalAddressesRequest`
- `SearchContactAdditionalAddressesRequest`
- `DeleteAContactAdditionalAddressRequest`

**⚠️ MAJOR BREAKING CHANGES** - The authentication system has been completely redesigned to support OAuth alongside token authentication.

##### BexioConnector Constructor Changes

**Before (Token only):**
```php
// Old constructor - DEPRECATED
$connector = new BexioConnector($token);
$connector = new BexioConnector(); // Used config('bexio.auth.token')
```

**After (OAuth + Token support):**
```php
// New constructor - REQUIRED
use CodebarAg\Bexio\Dto\OAuthConfiguration\ConnectWithToken;
use CodebarAg\Bexio\Dto\OAuthConfiguration\ConnectWithOAuth;

// Token authentication
$connector = new BexioConnector(new ConnectWithToken($token));
$connector = new BexioConnector(new ConnectWithToken()); // Uses config

// OAuth authentication
$connector = new BexioConnector(new ConnectWithOAuth($clientId, $clientSecret, $redirectUri, $scopes));
$connector = new BexioConnector(new ConnectWithOAuth()); // Uses config

// Auto-resolve from container (default behavior)
$connector = new BexioConnector(); // Will resolve OAuth config if available
```

##### Configuration Structure Changes

**Before:**
```php
// config/bexio.php
return [
'auth' => [
'token' => env('BEXIO_API_TOKEN'),
],
];
```

**After:**
```php
// config/bexio.php
return [
'auth' => [
'token' => env('BEXIO_API_TOKEN'),
'oauth' => [
'client_id' => env('BEXIO_OAUTH_CLIENT_ID'),
'client_secret' => env('BEXIO_OAUTH_CLIENT_SECRET'),
'redirect_uri' => env('BEXIO_OAUTH_REDIRECT_URI'),
'scopes' => explode(',', env('BEXIO_OAUTH_SCOPES')),
],
],
'cache_store' => env('BEXIO_CACHE_STORE'),
'route_prefix' => null,
'redirect_url' => env('BEXIO_REDIRECT_URL', ''),
];
```

##### New Environment Variables Required

Add these new environment variables for OAuth support:

```dotenv
# OAuth Authentication (NEW)
BEXIO_OAUTH_CLIENT_ID=your_client_id_here
BEXIO_OAUTH_CLIENT_SECRET=your_client_secret_here
BEXIO_OAUTH_REDIRECT_URI=https://yourapp.com/bexio/callback
BEXIO_OAUTH_SCOPES=openid,profile,email,accounting,contact_show

# Optional OAuth Configuration
BEXIO_CACHE_STORE=redis
BEXIO_REDIRECT_URL=/dashboard
```

##### Service Provider Changes

- New OAuth resolver contracts are automatically registered
- OAuth routes are automatically registered at `/bexio/redirect` and `/bexio/callback`
- Route prefix can be customized via `config('bexio.route_prefix')`

##### Migration Guide

1. **Update your BexioConnector instantiation:**
```php
// OLD - This will break
$connector = new BexioConnector($token);

// NEW - Required change
$connector = new BexioConnector(new ConnectWithToken($token));
```

2. **Publish and update config file:**
```bash
php artisan vendor:publish --provider="CodebarAg\Bexio\BexioServiceProvider" --tag="bexio-config" --force
```

3. **For OAuth usage:**
- Register your application in Bexio Developer Portal
- Add OAuth environment variables to `.env`
- Use `ConnectWithOAuth` for OAuth authentication
- Use built-in routes `/bexio/redirect` and `/bexio/callback`

4. **For multi-tenant applications:**
- Implement custom `BexioOAuthConfigResolver` interface
- Implement custom `BexioOAuthAuthenticationStoreResolver` interface
- Optionally implement custom `BexioOAuthAuthenticationValidateResolver` interface for validation logic
- Bind your implementations in a service provider

### ✨ New Features

- **OAuth 2.0 Support**: Full OAuth 2.0 implementation with PKCE support
- **Multi-tenant OAuth**: Support for multiple Bexio accounts via custom resolvers
- **OAuth Authentication Validation**: Custom validation logic before storing OAuth tokens with API access and custom redirects
- **Automatic Token Refresh**: OAuth tokens are automatically refreshed when expired
- **Encrypted Token Storage**: OAuth tokens are encrypted when cached
- **Built-in OAuth Routes**: Automatic OAuth flow handling
- **Configurable Cache Stores**: Support for custom cache stores for token storage
- **Comprehensive Scopes**: Support for all Bexio API and OpenID Connect scopes

#### OAuth Authentication Validation

The new `BexioOAuthAuthenticationValidateResolver` allows you to implement custom validation logic that runs after OAuth authentication but before the token is stored. This powerful feature provides:

- **API Access**: Full `BexioConnector` instance with authenticated access to Bexio API
- **Custom Validation**: Validate user permissions, company restrictions, or any business logic
- **Custom Redirects**: Return custom redirect responses with your own error handling
- **Exception Handling**: Gracefully handle API errors during validation

**Example Use Cases:**
- Validate user email against an allowlist
- Check company permissions via Bexio API calls
- Verify required OAuth scopes are present
- Implement custom business rules for authorization

**Default Behavior**: By default, all OAuth authentications are accepted (validation returns success)

### 🔧 Configuration

- **New OAuth Configuration**: Complete OAuth configuration structure
- **Route Customization**: Customizable OAuth route prefix
- **Cache Store Configuration**: Configurable cache store for token storage
- **Redirect URL Configuration**: Configurable post-authentication redirect

### 📚 Documentation

- **Updated README**: Comprehensive OAuth and multi-tenant documentation
- **OAuth Validation Documentation**: Complete guide for custom OAuth authentication validation with examples
- **Migration Examples**: Detailed migration examples for all scenarios
- **Scope Documentation**: Complete OAuth scope enumeration and documentation
**Migration:** Use `AdditionalAddresses` instead, which provides the same functionality with additional fields (`street_name`, `house_number`, `address_addition`, `name_addition`). All requests now use `contactId` as the parameter name for consistency.

### 🔄 DTO Field Updates

The following DTOs have been updated with new fields:
- **AdditionalAddresses requests:** Standardized parameter naming to use `contactId` instead of `id` for consistency across all requests. The following DTOs have been updated with new fields:

#### Contact & Additional Address Fields (2025-06-04)

Expand Down
44 changes: 23 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -710,7 +710,6 @@ We provide DTOs for the following:
| BusinessYearDTO |
| CalendarYearDTO |
| CompanyProfileDTO |
| ContactAdditionalAddressDTO |
| ContactGroupDTO |
| ContactRelationDTO |
| ContactDTO |
Expand Down Expand Up @@ -751,7 +750,6 @@ In addition to the above, we also provide DTOs to be used for create and edit re
|---------------------------------------|
| CreateCalendarYearDTO |
| CreateEditAdditionalAddressDTO |
| CreateEditContactAdditionalAddressDTO |
| CreateEditContactGroupDTO |
| CreateEditContactRelationDTO |
| CreateEditContactDTO |
Expand Down Expand Up @@ -858,7 +856,7 @@ $addresses = $connector->send(new SearchAddressesRequest(
* Create Address
*/
$address = $connector->send(new CreateAnAdditionalAddressRequest(
id: 1,
contactId: 1,
data: new CreateEditAdditionalAddressDTO(
name: 'Test',
subject: 'Test Subject',
Expand Down Expand Up @@ -974,28 +972,28 @@ $companyProfile = $connector->send(new FetchACompanyProfileRequest(
### Additional Addresses
```php
/**
* Fetch A List Of Contact Additional Addresses
* Fetch A List Of Additional Addresses
*/
$contactAdditionalAddresses = $connector->send(new FetchAListOfContactAdditionalAddressesRequest(
$additionalAddresses = $connector->send(new FetchAListOfAdditionalAddressesRequest(
contactId: 1
))->dto();
```

```php
/**
* Fetch A Contact Additional Address
* Fetch An Additional Address
*/
$contactAdditionalAddress = $connector->send(new FetchAContactAdditionalAddressRequest(
$additionalAddress = $connector->send(new FetchAnAdditionalAddressRequest(
contactId: 1,
id: 1
))->dto();
```

```php
/**
* Search Contact Additional Address
* Search Additional Addresses
*/
$contactAdditionalAddresses = $connector->send(new SearchContactAdditionalAddressesRequest(
$additionalAddresses = $connector->send(new SearchAdditionalAddressesRequest(
contactId: 1,
searchField: 'Name',
searchTerm: 'Something'
Expand All @@ -1004,44 +1002,48 @@ $contactAdditionalAddresses = $connector->send(new SearchContactAdditionalAddres

```php
/**
* Create Contact Additional Address
* Create Additional Address
*/
$contactAdditionalAddress = $connector->send(new CreateContactAdditionalAddressRequest(
$additionalAddress = $connector->send(new CreateAnAdditionalAddressRequest(
contactId: 1,
data: new CreateEditContactAdditionalAddressDTO(
data: new CreateEditAdditionalAddressDTO(
name: 'Test',
subject: 'Test Subject',
description: 'This is a test',
address: 'Test Address',
postcode: '1234',
street_name: 'Main Street',
house_number: '123',
address_addition: 'Apt 4B',
postcode: 1234,
city: 'Test City',
)
));
Comment on lines +1007 to 1019
Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The example is missing the required name_addition parameter for CreateEditAdditionalAddressDTO. According to the DTO definition, name_addition is a required parameter (not nullable). Add name_addition: null, or provide a value after the name parameter to match the DTO constructor signature.

Copilot uses AI. Check for mistakes.
```

```php
/**
* Edit Contact Additional Address
* Edit Additional Address
*/
$contactAdditionalAddress = $connector->send(new EditAContactAdditionalAddressRequest(
$additionalAddress = $connector->send(new EditAnAdditionalAddressRequest(
contactId: 1,
id: 9,
data: new CreateEditContactAdditionalAddressDTO(
data: new CreateEditAdditionalAddressDTO(
name: 'Test Edit',
subject: 'Test Subject Edit',
description: 'This is a test edit',
address: 'Test Address Edit',
postcode: '4567',
street_name: 'Main Street',
house_number: '456',
address_addition: 'Suite 2',
postcode: 4567,
city: 'Test City Edit',
)
));
Comment on lines +1026 to 1039
Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The example is missing the required name_addition parameter for CreateEditAdditionalAddressDTO. According to the DTO definition, name_addition is a required parameter (not nullable). Add name_addition: null, or provide a value after the name parameter to match the DTO constructor signature.

Copilot uses AI. Check for mistakes.
```

```php
/**
* Delete Contact Additional Address
* Delete Additional Address
*/
$contactAdditionalAddress = $connector->send(new DeleteAContactAdditionalAddressRequest(
$additionalAddress = $connector->send(new DeleteAnAdditionalAddressRequest(
contactId: 1,
id: 9,
));
Expand Down
51 changes: 0 additions & 51 deletions src/Dto/ContactAdditionalAddresses/ContactAdditionalAddressDTO.php

This file was deleted.

Loading