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
4 changes: 2 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ If it saves you or your team time, please consider [sponsoring its development](
### Breaking changes

* The SDK supports only actively supported PHP versions. As a result, support for PHP < 8.3 has been dropped;
supported versions are 8.3, 8.4, and 8.5.
supported versions are 8.3, 8.4, and 8.5.
* [Firebase Dynamic Links was shut down on August 25th, 2025](https://firebase.google.com/support/dynamic-links-faq)
and has been removed from the SDK.
* Deprecated classes, methods and class constants have been removed.
* Replaced `Stringable|string` argument types with `string`-only
* Type declarations have been simplified to reduce runtime overhead (e.g., `Stringable|string` to `string`).

See **[UPGRADE-8.0](UPGRADE-8.0.md) for more details on the changes between 7.x and 8.0.**

Expand Down
34 changes: 17 additions & 17 deletions UPGRADE-8.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,26 +12,16 @@ from 7.x to 8.0.
* [Firebase Dynamic Links was shut down on August 25th, 2025](https://firebase.google.com/support/dynamic-links-faq)
and has been removed from the SDK.

### Replaced `Stringable|string` argument types with `string`-only
### Type simplifications to reduce runtime overhead

Methods that previously accepted `Stringable|string` as argument types now only support `string`.
Several argument types have been simplified to their most common forms to eliminate runtime type conversion overhead.
For example, methods that previously accepted `Stringable|string` now only accept `string`.

`Stringable` was added for convenience so that someone could do, for example
The union types were originally added for convenience, but introduced overhead when processing arguments, requiring
runtime type conversion and validation that could be replaced with static analysis.

```php
$user = $auth->getUser('uid');
$auth->updateUser($user, [...]);
```

While convenient, this adds overhead when processing these arguments. For example, if a method expects a non-empty
string, the SDK would have to do a `trim((string) $arg)` and check if it's empty.

With this change, we can rely only on a `@var non-empty-string $arg` docblock annotation.

```php
$user = $auth->getUser('uid');
$auth->updateUser($user->uid, [...]);
```
**See the complete list of breaking changes below** to identify any adjustments needed. Most changes should (hopefully)
be trivial (e.g., passing `$user->uid` instead of `$user`). Run your test suite to catch any breaking changes.

## Complete list of breaking changes

Expand All @@ -41,6 +31,7 @@ The following list has been generated with [roave/backward-compatibility-check](
[BC] CHANGED: Default parameter value for parameter $code of Kreait\Firebase\Exception\Database\TransactionFailed#__construct() changed from 0 to NULL
[BC] CHANGED: Default parameter value for parameter $code of Kreait\Firebase\Exception\Database\UnsupportedQuery#__construct() changed from 0 to NULL
[BC] CHANGED: The number of required arguments for Kreait\Firebase\Exception\Database\UnsupportedQuery#__construct() increased from 1 to 2
[BC] CHANGED: The parameter $accessToken of Kreait\Firebase\Contract\Auth#signInWithIdpAccessToken() changed from string to Lcobucci\JWT\Token|string
[BC] CHANGED: The parameter $clearTextPassword of Kreait\Firebase\Contract\Auth#signInWithEmailAndPassword() changed from Stringable|string to a non-contravariant string
[BC] CHANGED: The parameter $clearTextPassword of Kreait\Firebase\Contract\Auth#signInWithEmailAndPassword() changed from Stringable|string to string
[BC] CHANGED: The parameter $clearTextPassword of Kreait\Firebase\Request\EditUserTrait#withClearTextPassword() changed from Stringable|string to a non-contravariant string
Expand All @@ -49,6 +40,8 @@ The following list has been generated with [roave/backward-compatibility-check](
[BC] CHANGED: The parameter $clearTextPassword of Kreait\Firebase\Request\EditUserTrait#withClearTextPassword() changed from Stringable|string to string
[BC] CHANGED: The parameter $code of Kreait\Firebase\Exception\Database\TransactionFailed#__construct() changed from int to a non-contravariant Throwable|null
[BC] CHANGED: The parameter $code of Kreait\Firebase\Exception\Database\UnsupportedQuery#__construct() changed from int to a non-contravariant Throwable|null
[BC] CHANGED: The parameter $config of Kreait\Firebase\Messaging\CloudMessage#withAndroidConfig() changed from no type to a non-contravariant Kreait\Firebase\Messaging\AndroidConfig|array
[BC] CHANGED: The parameter $config of Kreait\Firebase\Messaging\CloudMessage#withApnsConfig() changed from no type to a non-contravariant Kreait\Firebase\Messaging\ApnsConfig|array
[BC] CHANGED: The parameter $email of Kreait\Firebase\Contract\Auth#createUserWithEmailAndPassword() changed from Stringable|string to a non-contravariant string
[BC] CHANGED: The parameter $email of Kreait\Firebase\Contract\Auth#createUserWithEmailAndPassword() changed from Stringable|string to string
[BC] CHANGED: The parameter $email of Kreait\Firebase\Contract\Auth#getEmailActionLink() changed from Stringable|string to a non-contravariant string
Expand Down Expand Up @@ -110,6 +103,10 @@ The following list has been generated with [roave/backward-compatibility-check](
[BC] CHANGED: The parameter $providerId of Kreait\Firebase\Contract\Transitional\FederatedUserFetcher#getUserByProviderUid() changed from Stringable|string to string
[BC] CHANGED: The parameter $providerUid of Kreait\Firebase\Contract\Transitional\FederatedUserFetcher#getUserByProviderUid() changed from Stringable|string to a non-contravariant string
[BC] CHANGED: The parameter $providerUid of Kreait\Firebase\Contract\Transitional\FederatedUserFetcher#getUserByProviderUid() changed from Stringable|string to string
[BC] CHANGED: The parameter $redirectUrl of Kreait\Firebase\Contract\Auth#signInWithIdpAccessToken() changed from no type to a non-contravariant string|null
[BC] CHANGED: The parameter $redirectUrl of Kreait\Firebase\Contract\Auth#signInWithIdpAccessToken() changed from no type to string|null
[BC] CHANGED: The parameter $redirectUrl of Kreait\Firebase\Contract\Auth#signInWithIdpIdToken() changed from no type to a non-contravariant string|null
[BC] CHANGED: The parameter $redirectUrl of Kreait\Firebase\Contract\Auth#signInWithIdpIdToken() changed from no type to string|null
[BC] CHANGED: The parameter $uid of Kreait\Firebase\Contract\Auth#changeUserEmail() changed from Stringable|string to a non-contravariant string
[BC] CHANGED: The parameter $uid of Kreait\Firebase\Contract\Auth#changeUserEmail() changed from Stringable|string to string
[BC] CHANGED: The parameter $uid of Kreait\Firebase\Contract\Auth#changeUserPassword() changed from Stringable|string to a non-contravariant string
Expand Down Expand Up @@ -142,6 +139,9 @@ The following list has been generated with [roave/backward-compatibility-check](
[BC] CHANGED: The parameter $url of Kreait\Firebase\Request\EditUserTrait#withPhotoUrl() changed from Stringable|string to string
[BC] CHANGED: The parameter $user of Kreait\Firebase\Contract\Auth#signInAsUser() changed from Kreait\Firebase\Auth\UserRecord|Stringable|string to Kreait\Firebase\Auth\UserRecord|string
[BC] CHANGED: The parameter $user of Kreait\Firebase\Contract\Auth#signInAsUser() changed from Kreait\Firebase\Auth\UserRecord|Stringable|string to a non-contravariant Kreait\Firebase\Auth\UserRecord|string
[BC] CHANGED: The parameter $value of Kreait\Firebase\Messaging\ApnsConfig#withDataField() changed from mixed to a non-contravariant string
[BC] CHANGED: The parameter $value of Kreait\Firebase\RemoteConfig\ConditionalValue#withValue() changed from no type to Kreait\Firebase\RemoteConfig\ParameterValue|array|string
[BC] CHANGED: The parameter $value of Kreait\Firebase\RemoteConfig\ConditionalValue#withValue() changed from no type to a non-contravariant Kreait\Firebase\RemoteConfig\ParameterValue|array|string
[BC] CHANGED: The return type of Kreait\Firebase\RemoteConfig\ConditionalValue#value() changed from no type to string|array
[BC] CHANGED: The return type of Kreait\Firebase\RemoteConfig\TagColor#__toString() changed from no type to string
[BC] REMOVED: Class Kreait\Firebase\Contract\DynamicLinks has been deleted
Expand Down
5 changes: 3 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,16 +49,17 @@
"psr/http-message": "^1.1 || ^2.0"
},
"require-dev": {
"php-cs-fixer/shim": "^3.91.2",
"google/cloud-firestore": "^1.54.3",
"php-cs-fixer/shim": "^3.91.2",
"phpstan/extension-installer": "^1.4.3",
"phpstan/phpstan": "^2.1.32",
"phpstan/phpstan-deprecation-rules": "^2.0.3",
"phpstan/phpstan-strict-rules": "^2.0.7",
"phpstan/phpstan-phpunit": "^2.0.8",
"phpstan/phpstan-strict-rules": "^2.0.7",
"phpunit/phpunit": "^12.4.5",
"psr/log": "^3.0.2",
"rector/rector": "^2.2.11",
"rector/type-perfect": "^2.1",
"shipmonk/composer-dependency-analyser": "^1.8.4",
"symfony/var-dumper": "^7.4.0",
"vlucas/phpdotenv": "^5.6.2"
Expand Down
7 changes: 7 additions & 0 deletions phpstan.neon.dist
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,13 @@ parameters:
reportPossiblyNonexistentConstantArrayOffset: true
# reportPossiblyNonexistentGeneralArrayOffset: true
reportAnyTypeWideningInVarTag: true

type_perfect:
no_mixed_property: true
no_mixed_caller: true
null_over_false: true
narrow_param: false
narrow_return: true
includes:
- vendor/cuyz/valinor/qa/PHPStan/valinor-phpstan-configuration.php
- vendor/phpstan/phpstan/conf/bleedingEdge.neon
50 changes: 21 additions & 29 deletions src/Firebase/Auth.php
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ public function setCustomUserClaims(string $uid, ?array $claims): void
$this->client->setCustomUserClaims($uid, $claims);
}

public function createCustomToken(string $uid, array $claims = [], $ttl = 3600): UnencryptedToken
public function createCustomToken(string $uid, array $claims = [], int|DateInterval|string $ttl = 3600): UnencryptedToken
{
if ($this->tokenGenerator === null) {
throw new AuthError('Custom Token Generation is disabled because the current credentials do not permit it');
Expand Down Expand Up @@ -395,7 +395,7 @@ public function parseToken(string $tokenString): UnencryptedToken
return $parsedToken;
}

public function verifyIdToken($idToken, bool $checkIfRevoked = false, ?int $leewayInSeconds = null): UnencryptedToken
public function verifyIdToken(Token|string $idToken, bool $checkIfRevoked = false, ?int $leewayInSeconds = null): UnencryptedToken
{
$verifier = $this->idTokenVerifier;

Expand Down Expand Up @@ -481,7 +481,7 @@ public function verifyPasswordResetCode(string $oobCode): string
return $responseData['email'];
}

public function confirmPasswordReset(string $oobCode, $newPassword, bool $invalidatePreviousSessions = true): string
public function confirmPasswordReset(string $oobCode, string $newPassword, bool $invalidatePreviousSessions = true): string
{
$newPassword = ClearTextPassword::fromString($newPassword)->value;

Expand All @@ -508,7 +508,7 @@ public function revokeRefreshTokens(string $uid): void
$this->client->revokeRefreshTokens($uid);
}

public function unlinkProvider($uid, $provider): UserRecord
public function unlinkProvider(string $uid, array|string $provider): UserRecord
{
$uid = Uid::fromString($uid)->value;

Expand All @@ -519,7 +519,7 @@ public function unlinkProvider($uid, $provider): UserRecord
return $this->getUserRecordFromResponseAfterUserUpdate($response);
}

public function signInAsUser($user, ?array $claims = null): SignInResult
public function signInAsUser(UserRecord|string $user, ?array $claims = null): SignInResult
{
$claims ??= [];
$uid = $user instanceof UserRecord ? $user->uid : $user;
Expand All @@ -533,7 +533,7 @@ public function signInAsUser($user, ?array $claims = null): SignInResult
return $this->client->handleSignIn(SignInWithCustomToken::fromValue($customToken->toString()));
}

public function signInWithCustomToken($token): SignInResult
public function signInWithCustomToken(Token|string $token): SignInResult
{
$token = $token instanceof Token ? $token->toString() : $token;

Expand All @@ -547,15 +547,15 @@ public function signInWithRefreshToken(string $refreshToken): SignInResult
return $this->client->handleSignIn(SignInWithRefreshToken::fromValue($refreshToken));
}

public function signInWithEmailAndPassword($email, $clearTextPassword): SignInResult
public function signInWithEmailAndPassword(string $email, string $clearTextPassword): SignInResult
{
$email = Email::fromString($email)->value;
$clearTextPassword = ClearTextPassword::fromString($clearTextPassword)->value;

return $this->client->handleSignIn(SignInWithEmailAndPassword::fromValues($email, $clearTextPassword));
}

public function signInWithEmailAndOobCode($email, string $oobCode): SignInResult
public function signInWithEmailAndOobCode(string $email, string $oobCode): SignInResult
{
$email = Email::fromString($email)->value;

Expand All @@ -578,62 +578,54 @@ public function signInAnonymously(): SignInResult
throw new FailedToSignIn('Failed to sign in anonymously: No ID token or UID available');
}

public function signInWithIdpAccessToken($provider, string $accessToken, $redirectUrl = null, ?string $oauthTokenSecret = null, ?string $linkingIdToken = null, ?string $rawNonce = null): SignInResult
public function signInWithIdpAccessToken(string $provider, Token|string $accessToken, ?string $redirectUrl = null, ?string $oauthTokenSecret = null, ?string $linkingIdToken = null, ?string $rawNonce = null): SignInResult
{
$redirectUrl = trim((string) ($redirectUrl ?? 'http://localhost'));
$linkingIdToken = trim((string) $linkingIdToken);
$oauthTokenSecret = trim((string) $oauthTokenSecret);
$rawNonce = trim((string) $rawNonce);
$accessToken = $accessToken instanceof Token ? $accessToken->toString() : $accessToken;
$redirectUrl = trim($redirectUrl ?? 'http://localhost');

if ($oauthTokenSecret !== '') {
if ($oauthTokenSecret !== null) {
$action = SignInWithIdpCredentials::withAccessTokenAndOauthTokenSecret($provider, $accessToken, $oauthTokenSecret);
} else {
$action = SignInWithIdpCredentials::withAccessToken($provider, $accessToken);
}

if ($linkingIdToken !== '') {
if ($linkingIdToken !== null) {
$action = $action->withLinkingIdToken($linkingIdToken);
}

if ($rawNonce !== '') {
if ($rawNonce !== null) {
$action = $action->withRawNonce($rawNonce);
}

if ($redirectUrl !== '') {
$action = $action->withRequestUri($redirectUrl);
}
$action = $action->withRequestUri($redirectUrl);

return $this->client->handleSignIn($action);
}

public function signInWithIdpIdToken($provider, $idToken, $redirectUrl = null, ?string $linkingIdToken = null, ?string $rawNonce = null): SignInResult
public function signInWithIdpIdToken(string $provider, Token|string $idToken, ?string $redirectUrl = null, ?string $linkingIdToken = null, ?string $rawNonce = null): SignInResult
{
$redirectUrl = trim((string) ($redirectUrl ?? 'http://localhost'));
$linkingIdToken = trim((string) $linkingIdToken);
$rawNonce = trim((string) $rawNonce);
$redirectUrl = trim(($redirectUrl ?? 'http://localhost'));

if ($idToken instanceof Token) {
$idToken = $idToken->toString();
}

$action = SignInWithIdpCredentials::withIdToken($provider, $idToken);

if ($rawNonce !== '') {
if ($rawNonce !== null) {
$action = $action->withRawNonce($rawNonce);
}

if ($linkingIdToken !== '') {
if ($linkingIdToken !== null) {
$action = $action->withLinkingIdToken($linkingIdToken);
}

if ($redirectUrl !== '') {
$action = $action->withRequestUri($redirectUrl);
}
$action = $action->withRequestUri($redirectUrl);

return $this->client->handleSignIn($action);
}

public function createSessionCookie($idToken, $ttl): string
public function createSessionCookie(Token|string $idToken, DateInterval|int $ttl): string
{
if ($idToken instanceof Token) {
$idToken = $idToken->toString();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
use Kreait\Firebase\Auth\ProjectAwareAuthResourceUrlBuilder;
use Kreait\Firebase\Auth\TenantAwareAuthResourceUrlBuilder;
use Psr\Http\Client\ClientExceptionInterface;
use Psr\Http\Message\RequestInterface;

use function array_filter;

Expand Down Expand Up @@ -68,7 +67,7 @@ public function handle(CreateActionLink $action): string
return (string) $actionCode;
}

private function createRequest(CreateActionLink $action): RequestInterface
private function createRequest(CreateActionLink $action): Request
{
$data = [
'requestType' => $action->type(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
use Kreait\Firebase\Auth\ProjectAwareAuthResourceUrlBuilder;
use Kreait\Firebase\Auth\TenantAwareAuthResourceUrlBuilder;
use Psr\Http\Client\ClientExceptionInterface;
use Psr\Http\Message\RequestInterface;

use function array_filter;

Expand Down Expand Up @@ -63,7 +62,7 @@ public function handle(CreateSessionCookie $action): string
throw new FailedToCreateSessionCookie($action, $response, 'The response did not contain a session cookie');
}

private function createRequest(CreateSessionCookie $action): RequestInterface
private function createRequest(CreateSessionCookie $action): Request
{
$data = [
'idToken' => $action->idToken(),
Expand Down
3 changes: 1 addition & 2 deletions src/Firebase/Auth/SendActionLink/GuzzleApiClientHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
use Kreait\Firebase\Auth\SendActionLink;
use Kreait\Firebase\Auth\TenantAwareAuthResourceUrlBuilder;
use Psr\Http\Client\ClientExceptionInterface;
use Psr\Http\Message\RequestInterface;

use function array_filter;

Expand Down Expand Up @@ -50,7 +49,7 @@ public function handle(SendActionLink $action): void
}
}

private function createRequest(SendActionLink $action): RequestInterface
private function createRequest(SendActionLink $action): Request
{
$data = [
'requestType' => $action->type(),
Expand Down
3 changes: 1 addition & 2 deletions src/Firebase/Auth/SignIn/GuzzleHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
use Kreait\Firebase\Auth\SignInWithRefreshToken;
use Kreait\Firebase\Util;
use Psr\Http\Client\ClientExceptionInterface;
use Psr\Http\Message\RequestInterface;
use UnexpectedValueException;

use function http_build_query;
Expand Down Expand Up @@ -77,7 +76,7 @@ public function handle(SignIn $action): SignInResult
return SignInResult::fromData($data);
}

private function createApiRequest(SignIn $action): RequestInterface
private function createApiRequest(SignIn $action): Request
{
return match (true) {
$action instanceof SignInAnonymously => $this->anonymous($action),
Expand Down
Loading
Loading