diff --git a/readme.md b/readme.md index 7964230..080a374 100644 --- a/readme.md +++ b/readme.md @@ -62,6 +62,7 @@ $config = [ 'clientId' => 'YOUR_CLIENT_ID', 'clientSecret' => 'YOUR_SECRET_API_KEY', 'apiBaseUrl' => 'https://api.frontegg.com/', + 'authenticationBaseUrl' => 'https://api.frontegg.com/', 'apiUrls' => [ 'authentication' => '/auth/vendor', 'audits' => '/audits', @@ -89,6 +90,7 @@ $frontegg->init(); | **clientSecret** | string | None | API Key. Required | | **contextResolver** | callable | None | Callback to provide context info. Required | | apiBaseUrl | string | https://api.frontegg.com | Base API URL | +| authenticationBaseUrl | string | https://api.frontegg.com | Base URL used for authentication | | apiUrls | array | [] | List of URLs of the API services | | disableCors | bool | false | Disabling CORS headers for Middleware Proxy | | httpClientHandler | special interface* | Curl client** | Custom HTTP client | diff --git a/src/Frontegg/Authenticator/Authenticator.php b/src/Frontegg/Authenticator/Authenticator.php index abf67c4..854de11 100644 --- a/src/Frontegg/Authenticator/Authenticator.php +++ b/src/Frontegg/Authenticator/Authenticator.php @@ -90,7 +90,7 @@ public function getLastResponse(): ?ApiRawResponse */ public function authenticate(): void { - $url = $this->fronteggConfig->getServiceUrl( + $url = $this->fronteggConfig->getAuthenticationUrl( Config::AUTHENTICATION_SERVICE ); $body = json_encode( diff --git a/src/Frontegg/Config/Config.php b/src/Frontegg/Config/Config.php index f1128fc..2442e51 100644 --- a/src/Frontegg/Config/Config.php +++ b/src/Frontegg/Config/Config.php @@ -53,6 +53,14 @@ class Config */ protected $baseUrl; + /** + * Frontegg API base URL for authentication. + * In hybrid mode, the base API url and authentication url may be different + * + * @var string + */ + protected $authenticationBaseUrl; + /** * Frontegg API endpoints relative URLs. * @@ -79,6 +87,7 @@ class Config * @param array $urls * @param bool $disableCors * @param callable $contextResolver + * @param string $authenticationBaseUrl */ public function __construct( string $clientId, @@ -86,7 +95,8 @@ public function __construct( string $baseUrl, array $urls, bool $disableCors, - callable $contextResolver + callable $contextResolver, + string $authenticationBaseUrl ) { $this->clientId = $clientId; $this->clientSecret = $clientSecret; @@ -94,6 +104,7 @@ public function __construct( $this->setApiUrls($urls); $this->contextResolver = $contextResolver; $this->disableCors = $disableCors; + $this->authenticationBaseUrl = trim($authenticationBaseUrl, '/'); } /** @@ -136,6 +147,14 @@ public function getBaseUrl(): string return $this->baseUrl; } + /** + * @return string + */ + public function getAuthenticationBaseUrl(): string + { + return $this->authenticationBaseUrl; + } + /** * Returns API URL by service name. * @@ -147,11 +166,7 @@ public function getBaseUrl(): string */ public function getServiceUrl(string $urlKey): string { - if (!isset(static::$API_URL_KEYS[$urlKey])) { - throw new InvalidUrlConfigException( - sprintf('URL "%s" is not a part of allowed API', $urlKey) - ); - } + $this->validateUrlKey($urlKey); if (isset($this->urls[$urlKey])) { return $this->baseUrl . $this->urls[$urlKey]; @@ -160,6 +175,17 @@ public function getServiceUrl(string $urlKey): string return $this->baseUrl . static::$API_URL_KEYS[$urlKey]; } + public function getAuthenticationUrl(string $urlKey): string + { + $this->validateUrlKey($urlKey); + + if (isset($this->urls[$urlKey])) { + return $this->authenticationBaseUrl . $this->urls[$urlKey]; + } + + return $this->authenticationBaseUrl . static::$API_URL_KEYS[$urlKey]; + } + /** * Returns URL of the Frontegg proxy. * @@ -189,4 +215,13 @@ protected function setApiUrls(array $urls = []): void $this->urls[$key] = $url; } } + + private function validateUrlKey(string $urlKey): void + { + if (!isset(static::$API_URL_KEYS[$urlKey])) { + throw new InvalidUrlConfigException( + sprintf('URL "%s" is not a part of allowed API', $urlKey) + ); + } + } } diff --git a/src/Frontegg/Frontegg.php b/src/Frontegg/Frontegg.php index cd8c8dc..09afc94 100644 --- a/src/Frontegg/Frontegg.php +++ b/src/Frontegg/Frontegg.php @@ -102,6 +102,7 @@ public function __construct(array $config = []) 'clientId' => getenv(static::CLIENT_ID_ENV_NAME), 'clientSecret' => getenv(static::CLIENT_SECRET_ENV_NAME), 'apiBaseUrl' => static::DEFAULT_API_BASE_URL, + 'authenticationBaseUrl' => static::DEFAULT_API_BASE_URL, 'apiUrls' => [], 'apiVersion' => static::DEFAULT_API_VERSION, 'httpClientHandler' => null, @@ -138,7 +139,8 @@ public function __construct(array $config = []) $config['apiBaseUrl'], $config['apiUrls'], $config['disableCors'], - $config['contextResolver'] + $config['contextResolver'], + $config['authenticationBaseUrl'] ); $this->client = $config['httpClientHandler'] ?? new FronteggCurlHttpClient(); diff --git a/tests/Authenticator/AuthenticatorTest.php b/tests/Authenticator/AuthenticatorTest.php index d1c78c5..19dc738 100644 --- a/tests/Authenticator/AuthenticatorTest.php +++ b/tests/Authenticator/AuthenticatorTest.php @@ -3,7 +3,9 @@ namespace Frontegg\Tests\Authenticator; use DateTime; +use Frontegg\HttpClient\FronteggCurlHttpClient; use Frontegg\Tests\Helper\AuthenticatorTestCaseHelper; +use Prophecy\Argument; class AuthenticatorTest extends AuthenticatorTestCaseHelper { @@ -168,4 +170,32 @@ public function testAuthenticationValidationIsNotWorking(): void $authenticator->getApiError()->getError() ); } + + public function testAuthenticatorCallsAuthUrl() + { + $authBaseUrl = 'http://authentication'; + + $client = $this->prophesize(FronteggCurlHttpClient::class); + $client->send( + Argument::containingString($authBaseUrl), + Argument::any(), + Argument::any(), + Argument::any(), + Argument::any() + ) + ->shouldBeCalledOnce() + ->willReturn($this->createAuthHttpApiRawResponse()); + + $authenticator = $this->createFronteggAuthenticator( + $client->reveal(), + 'clientTestID', + 'apiTestSecretKey', + 'http://test', + [], + true, + null, + $authBaseUrl + ); + $authenticator->authenticate(); + } } diff --git a/tests/Config/ConfigTest.php b/tests/Config/ConfigTest.php index 244f4e6..bd0d94d 100644 --- a/tests/Config/ConfigTest.php +++ b/tests/Config/ConfigTest.php @@ -23,7 +23,8 @@ public function testConfigHasClientCredentials(): void false, function (RequestInterface $request) { return []; - } + }, + 'https://auth/' ); // Assert @@ -52,14 +53,16 @@ public function testConfigHasApiUrls(): void false, function (RequestInterface $request) { return []; - } + }, + 'https://auth/' ); // Assert $this->assertEquals('https://api.frontegg.com', $config->getBaseUrl()); + $this->assertEquals('https://auth', $config->getAuthenticationBaseUrl()); $this->assertEquals( - 'https://api.frontegg.com/test/auth', - $config->getServiceUrl(Config::AUTHENTICATION_SERVICE) + 'https://auth/test/auth', + $config->getAuthenticationUrl(Config::AUTHENTICATION_SERVICE) ); $this->assertEquals( 'https://api.frontegg.com/audits', @@ -96,18 +99,28 @@ public function testConfigHasDefaultApiUrls(): void false, function (RequestInterface $request) { return []; - } + }, + 'https://auth/' ); // Assert $this->assertEquals( - $config->getBaseUrl() . Config::AUTHENTICATION_SERVICE_DEFAULT_URL, - $config->getServiceUrl(Config::AUTHENTICATION_SERVICE) + $config->getAuthenticationBaseUrl() . Config::AUTHENTICATION_SERVICE_DEFAULT_URL, + $config->getAuthenticationUrl(Config::AUTHENTICATION_SERVICE) + ); + $this->assertEquals( + $config->getBaseUrl() . Config::EVENTS_SERVICE_DEFAULT_URL, + $config->getServiceUrl(Config::EVENTS_SERVICE) ); $this->expectException(InvalidUrlConfigException::class); $this->assertNotEquals( 'should not be in the config', $config->getServiceUrl('randomUrl') ); + $this->expectException(InvalidUrlConfigException::class); + $this->assertNotEquals( + 'should not be in the config', + $config->getAuthenticationUrl('randomUrl') + ); } } diff --git a/tests/FronteggTest.php b/tests/FronteggTest.php index f1d7bba..11cb4a2 100644 --- a/tests/FronteggTest.php +++ b/tests/FronteggTest.php @@ -49,6 +49,14 @@ public function testFronteggAuthenticatorIsCreated(): void 'apiTestSecretKey', $frontegg->getConfig()->getClientSecret() ); + $this->assertEquals( + Frontegg::DEFAULT_API_BASE_URL, + $frontegg->getConfig()->getBaseUrl() + ); + $this->assertEquals( + Frontegg::DEFAULT_API_BASE_URL, + $frontegg->getConfig()->getAuthenticationBaseUrl() + ); $this->assertInstanceOf( FronteggHttpClientInterface::class, $frontegg->getClient() diff --git a/tests/Helper/AuthenticatorTestCaseHelper.php b/tests/Helper/AuthenticatorTestCaseHelper.php index 37be405..e82389b 100644 --- a/tests/Helper/AuthenticatorTestCaseHelper.php +++ b/tests/Helper/AuthenticatorTestCaseHelper.php @@ -28,7 +28,8 @@ protected function createFronteggAuthenticator( string $baseUrl = 'http://test', array $urls = [], bool $disbaleCors = true, - ?callable $contextResolver = null + ?callable $contextResolver = null, + string $authenticationBaseUrl = 'http://auth' ): Authenticator { $contextResolver = $contextResolver ?? function () { return []; @@ -39,7 +40,8 @@ protected function createFronteggAuthenticator( $baseUrl, $urls, $disbaleCors, - $contextResolver + $contextResolver, + $authenticationBaseUrl ); return new Authenticator($fronteggConfig, $client);