Skip to content

Commit 40894d1

Browse files
committed
feat: add TransportOptions for configuring TLS, proxy, and default headers (#70)
1 parent e0df5d5 commit 40894d1

20 files changed

+647
-107
lines changed

README.md

Lines changed: 90 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ JSON file. This process creates a secure token.
7474
**Example:**
7575

7676
```php
77-
use \Zitadel\Client\Zitadel;
77+
use Zitadel\Client\Zitadel;
7878

7979
$zitadel = Zitadel::withPrivateKey("https://example.us1.zitadel.cloud", "path/to/jwt-key.json");
8080

@@ -93,6 +93,7 @@ try {
9393
echo "User created: " . print_r($response, true);
9494
} catch (ApiException $e) {
9595
echo "Error: " . $e->getMessage();
96+
}
9697
```
9798

9899
#### 2. Client Credentials Grant
@@ -116,9 +117,8 @@ which is then used to authenticate.
116117
```php
117118
use Zitadel\Client\Zitadel;
118119
use Zitadel\Client\Model\UserServiceAddHumanUserRequest;
119-
use \Zitadel\Client\Model\UserServiceAddHumanUserRequest;
120-
use \Zitadel\Client\Model\UserServiceSetHumanProfile;
121-
use \Zitadel\Client\Model\UserServiceSetHumanEmail;
120+
use Zitadel\Client\Model\UserServiceSetHumanProfile;
121+
use Zitadel\Client\Model\UserServiceSetHumanEmail;
122122

123123
$zitadel = Zitadel::withClientCredentials("https://example.us1.zitadel.cloud", "id", "secret");
124124

@@ -159,12 +159,10 @@ authenticate without exchanging credentials every time.
159159
**Example:**
160160

161161
```php
162-
use \Zitadel\Client\Zitadel;
163162
use Zitadel\Client\Zitadel;
164163
use Zitadel\Client\Model\UserServiceAddHumanUserRequest;
165-
use \Zitadel\Client\Model\UserServiceAddHumanUserRequest;
166-
use \Zitadel\Client\Model\UserServiceSetHumanProfile;
167-
use \Zitadel\Client\Model\UserServiceSetHumanEmail;
164+
use Zitadel\Client\Model\UserServiceSetHumanProfile;
165+
use Zitadel\Client\Model\UserServiceSetHumanEmail;
168166

169167
$zitadel = Zitadel::withAccessToken("https://example.us1.zitadel.cloud", "token");
170168

@@ -194,6 +192,90 @@ Choose the authentication method that best suits your needs based on your
194192
environment and security requirements. For more details, please refer to the
195193
[Zitadel documentation on authenticating service users](https://zitadel.com/docs/guides/integrate/service-users/authenticate-service-users).
196194

195+
## Advanced Configuration
196+
197+
The SDK provides a `TransportOptions` object that allows you to customise
198+
the underlying HTTP transport used for both OpenID discovery and API calls.
199+
200+
### Disabling TLS Verification
201+
202+
In development or testing environments with self-signed certificates, you can
203+
disable TLS verification entirely:
204+
205+
```php
206+
use Zitadel\Client\Zitadel;
207+
use Zitadel\Client\TransportOptions;
208+
209+
$options = new TransportOptions(insecure: true);
210+
211+
$zitadel = Zitadel::withClientCredentials(
212+
'https://your-instance.zitadel.cloud',
213+
'client-id',
214+
'client-secret',
215+
$options,
216+
);
217+
```
218+
219+
### Using a Custom CA Certificate
220+
221+
If your Zitadel instance uses a certificate signed by a private CA, you can
222+
provide the path to the CA certificate in PEM format:
223+
224+
```php
225+
use Zitadel\Client\Zitadel;
226+
use Zitadel\Client\TransportOptions;
227+
228+
$options = new TransportOptions(caCertPath: '/path/to/ca.pem');
229+
230+
$zitadel = Zitadel::withClientCredentials(
231+
'https://your-instance.zitadel.cloud',
232+
'client-id',
233+
'client-secret',
234+
$options,
235+
);
236+
```
237+
238+
### Custom Default Headers
239+
240+
You can attach default headers to every outgoing request. This is useful for
241+
custom routing or tracing headers:
242+
243+
```php
244+
use Zitadel\Client\Zitadel;
245+
use Zitadel\Client\TransportOptions;
246+
247+
$options = new TransportOptions(
248+
defaultHeaders: ['X-Custom-Header' => 'my-value'],
249+
);
250+
251+
$zitadel = Zitadel::withClientCredentials(
252+
'https://your-instance.zitadel.cloud',
253+
'client-id',
254+
'client-secret',
255+
$options,
256+
);
257+
```
258+
259+
### Proxy Configuration
260+
261+
If your environment requires routing traffic through an HTTP proxy, you can
262+
specify the proxy URL. To authenticate with the proxy, embed the credentials
263+
directly in the URL:
264+
265+
```php
266+
use Zitadel\Client\Zitadel;
267+
use Zitadel\Client\TransportOptions;
268+
269+
$options = new TransportOptions(proxyUrl: 'http://user:pass@proxy:8080');
270+
271+
$zitadel = Zitadel::withClientCredentials(
272+
'https://your-instance.zitadel.cloud',
273+
'client-id',
274+
'client-secret',
275+
$options,
276+
);
277+
```
278+
197279
## Design and Dependencies
198280

199281
This SDK is designed to be lean and efficient, focusing on providing a

composer.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,14 @@
2727
"guzzlehttp/psr7": "^1.7 || ^2.0",
2828
"firebase/php-jwt": "^7.0.0",
2929
"league/oauth2-client": "^2.8",
30-
"league/uri": "^7.5"
30+
"league/uri": "^7.5",
31+
"ext-openssl": "*"
3132
},
3233
"require-dev": {
3334
"phpunit/phpunit": "^12.0",
3435
"friendsofphp/php-cs-fixer": "^3.75",
3536
"haydenpierce/class-finder": "^0.5.3",
3637
"testcontainers/testcontainers": "^1.0",
37-
"ext-openssl": "*",
3838
"ext-dom": "*",
3939
"vlucas/phpdotenv": "^5.6",
4040
"rector/rector": "^2.0",

composer.lock

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/Auth/ClientCredentialsAuthenticator.php

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
namespace Zitadel\Client\Auth;
44

55
use Exception;
6+
use GuzzleHttp\Client;
67
use League\OAuth2\Client\Provider\GenericProvider;
8+
use Zitadel\Client\TransportOptions;
79

810
/**
911
* OAuth2 Client Credentials Authenticator.
@@ -21,20 +23,27 @@ class ClientCredentialsAuthenticator extends OAuthAuthenticator
2123
* @param string $clientId The OAuth2 client identifier.
2224
* @param string $clientSecret The OAuth2 client secret.
2325
* @param string $scope The scope for the token request.
26+
* @param TransportOptions|null $transportOptions Optional transport options for TLS, proxy, and headers.
2427
*/
2528
public function __construct(
2629
OpenId $hostName,
2730
string $clientId,
2831
string $clientSecret,
29-
string $scope = 'openid urn:zitadel:iam:org:project:id:zitadel:aud'
32+
string $scope = 'openid urn:zitadel:iam:org:project:id:zitadel:aud',
33+
?TransportOptions $transportOptions = null
3034
) {
35+
$transportOptions ??= TransportOptions::defaults();
36+
37+
$guzzleOpts = $transportOptions->toGuzzleOptions();
38+
$collaborators = !empty($guzzleOpts) ? ['httpClient' => new Client($guzzleOpts)] : [];
39+
3140
parent::__construct($hostName, $clientId, $scope, new GenericProvider([
3241
'clientId' => $clientId,
3342
'clientSecret' => $clientSecret,
3443
'urlAccessToken' => $hostName->getTokenEndpoint()->toString(),
3544
'urlAuthorize' => $hostName->getAuthorizationEndpoint()->toString(),
3645
'urlResourceOwnerDetails' => $hostName->getUserinfoEndpoint()->toString(),
37-
]));
46+
], $collaborators), $transportOptions);
3847
}
3948

4049
/**
@@ -43,12 +52,17 @@ public function __construct(
4352
* @param string $host The base URL for API endpoints.
4453
* @param string $clientId The OAuth2 client identifier.
4554
* @param string $clientSecret The OAuth2 client secret.
55+
* @param TransportOptions|null $transportOptions Optional transport options for TLS, proxy, and headers.
4656
* @return ClientCredentialsAuthenticatorBuilder A new builder instance.
4757
* @throws Exception
4858
*/
49-
public static function builder(string $host, string $clientId, string $clientSecret): ClientCredentialsAuthenticatorBuilder
50-
{
51-
return new ClientCredentialsAuthenticatorBuilder($host, $clientId, $clientSecret);
59+
public static function builder(
60+
string $host,
61+
string $clientId,
62+
string $clientSecret,
63+
?TransportOptions $transportOptions = null,
64+
): ClientCredentialsAuthenticatorBuilder {
65+
return new ClientCredentialsAuthenticatorBuilder($host, $clientId, $clientSecret, $transportOptions);
5266
}
5367

5468
protected function getGrantType(): string

lib/Auth/ClientCredentialsAuthenticatorBuilder.php

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace Zitadel\Client\Auth;
44

55
use Exception;
6+
use Zitadel\Client\TransportOptions;
67

78
/**
89
* Builder for ClientCredentialsAuthenticator.
@@ -18,11 +19,16 @@ final class ClientCredentialsAuthenticatorBuilder extends OAuthAuthenticatorBuil
1819
* @param string $host The base URL for API endpoints.
1920
* @param string $clientId The OAuth2 client identifier.
2021
* @param string $clientSecret The OAuth2 client secret.
22+
* @param TransportOptions|null $transportOptions Optional transport options for TLS, proxy, and headers.
2123
* @throws Exception
2224
*/
23-
public function __construct(string $host, private readonly string $clientId, private readonly string $clientSecret)
24-
{
25-
parent::__construct($host);
25+
public function __construct(
26+
string $host,
27+
private readonly string $clientId,
28+
private readonly string $clientSecret,
29+
?TransportOptions $transportOptions = null,
30+
) {
31+
parent::__construct($host, $transportOptions);
2632
}
2733

2834
/**
@@ -36,7 +42,8 @@ public function build(): ClientCredentialsAuthenticator
3642
$this->hostName,
3743
$this->clientId,
3844
$this->clientSecret,
39-
$this->authScopes
45+
$this->authScopes,
46+
$this->transportOptions
4047
);
4148
}
4249
}

lib/Auth/OAuthAuthenticator.php

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use League\OAuth2\Client\Provider\GenericProvider;
77
use League\OAuth2\Client\Token\AccessTokenInterface;
88
use Throwable;
9+
use Zitadel\Client\TransportOptions;
910
use Zitadel\Client\ZitadelException;
1011

1112
/**
@@ -28,6 +29,12 @@ abstract class OAuthAuthenticator extends Authenticator
2829
* @var AccessTokenInterface|null
2930
*/
3031
protected ?AccessTokenInterface $token;
32+
/**
33+
* Transport options for HTTP connections.
34+
*
35+
* @var TransportOptions
36+
*/
37+
protected TransportOptions $transportOptions;
3138

3239
/**
3340
* OAuthAuthenticator constructor.
@@ -36,18 +43,20 @@ abstract class OAuthAuthenticator extends Authenticator
3643
* @param string $clientId The OAuth2 client identifier.
3744
* @param string $scope The scope for the token request.
3845
* @param GenericProvider $provider
46+
* @param TransportOptions|null $transportOptions Optional transport options for TLS, proxy, and headers.
3947
*/
4048
public function __construct(OpenId $openId, /**
4149
* The OAuth2 client identifier.
4250
*/
4351
protected string $clientId, /**
4452
* The scope for the token request.
4553
*/
46-
protected string $scope, protected GenericProvider $provider)
54+
protected string $scope, protected GenericProvider $provider, ?TransportOptions $transportOptions = null)
4755
{
4856
parent::__construct($openId->getHostEndpoint()->toString());
4957
$this->token = null;
5058
$this->openId = $openId;
59+
$this->transportOptions = $transportOptions ?? TransportOptions::defaults();
5160
}
5261

5362
/**

lib/Auth/OAuthAuthenticatorBuilder.php

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace Zitadel\Client\Auth;
44

55
use Exception;
6+
use Zitadel\Client\TransportOptions;
67

78
/**
89
* Base builder for OAuth authenticators.
@@ -14,16 +15,21 @@ abstract class OAuthAuthenticatorBuilder
1415
{
1516
protected OpenId $hostName;
1617
protected string $authScopes = 'openid urn:zitadel:iam:org:project:id:zitadel:aud';
18+
protected TransportOptions $transportOptions;
1719

1820
/**
1921
* Constructs the builder with the required host.
2022
*
2123
* @param string $hostName
24+
* @param TransportOptions|null $transportOptions Optional transport options for TLS, proxy, and headers.
2225
* @throws Exception
2326
*/
24-
public function __construct(string $hostName)
25-
{
26-
$this->hostName = new OpenId($hostName);
27+
public function __construct(
28+
string $hostName,
29+
?TransportOptions $transportOptions = null,
30+
) {
31+
$this->transportOptions = $transportOptions ?? TransportOptions::defaults();
32+
$this->hostName = new OpenId($hostName, $this->transportOptions);
2733
}
2834

2935
/**

0 commit comments

Comments
 (0)