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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ If it saves you or your team time, please consider [sponsoring its development](
* [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

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

Expand Down
124 changes: 120 additions & 4 deletions UPGRADE-8.0.md

Large diffs are not rendered by default.

73 changes: 30 additions & 43 deletions src/Firebase/Auth.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@
use Lcobucci\JWT\UnencryptedToken;
use Psr\Clock\ClockInterface;
use Psr\Http\Message\ResponseInterface;
use Stringable;
use Throwable;
use Traversable;

Expand Down Expand Up @@ -76,7 +75,7 @@ public function __construct(
$this->jwtParser = new Parser(new JoseEncoder());
}

public function getUser(Stringable|string $uid): UserRecord
public function getUser(string $uid): UserRecord
{
$uid = Uid::fromString($uid)->value;

Expand All @@ -91,7 +90,7 @@ public function getUser(Stringable|string $uid): UserRecord

public function getUsers(array $uids): array
{
$uids = array_map(static fn(\Stringable|string $uid): string => Uid::fromString($uid)->value, $uids);
$uids = array_map(static fn(string $uid): string => Uid::fromString($uid)->value, $uids);

$users = array_fill_keys($uids, null);

Expand Down Expand Up @@ -161,7 +160,7 @@ public function createUser(array|CreateUser $properties): UserRecord
return $this->getUserRecordFromResponseAfterUserUpdate($response);
}

public function updateUser(Stringable|string $uid, array|UpdateUser $properties): UserRecord
public function updateUser(string $uid, array|UpdateUser $properties): UserRecord
{
$request = $properties instanceof UpdateUser
? $properties
Expand All @@ -174,7 +173,7 @@ public function updateUser(Stringable|string $uid, array|UpdateUser $properties)
return $this->getUserRecordFromResponseAfterUserUpdate($response);
}

public function createUserWithEmailAndPassword(Stringable|string $email, Stringable|string $password): UserRecord
public function createUserWithEmailAndPassword(string $email, string $password): UserRecord
{
return $this->createUser(
CreateUser::new()
Expand All @@ -183,9 +182,9 @@ public function createUserWithEmailAndPassword(Stringable|string $email, Stringa
);
}

public function getUserByEmail(Stringable|string $email): UserRecord
public function getUserByEmail(string $email): UserRecord
{
$email = Email::fromString((string) $email)->value;
$email = Email::fromString($email)->value;

$response = $this->client->getUserByEmail($email);

Expand All @@ -198,10 +197,8 @@ public function getUserByEmail(Stringable|string $email): UserRecord
return $userRecord;
}

public function getUserByPhoneNumber(Stringable|string $phoneNumber): UserRecord
public function getUserByPhoneNumber(string $phoneNumber): UserRecord
{
$phoneNumber = (string) $phoneNumber;

$response = $this->client->getUserByPhoneNumber($phoneNumber);

$userRecord = self::getFirstUserRecordFromUserListResponse($response);
Expand All @@ -213,11 +210,8 @@ public function getUserByPhoneNumber(Stringable|string $phoneNumber): UserRecord
return $userRecord;
}

public function getUserByProviderUid(Stringable|string $providerId, Stringable|string $providerUid): UserRecord
public function getUserByProviderUid(string $providerId, string $providerUid): UserRecord
{
$providerId = (string) $providerId;
$providerUid = (string) $providerUid;

$response = $this->client->getUserByProviderUid($providerId, $providerUid);

$userRecord = self::getFirstUserRecordFromUserListResponse($response);
Expand All @@ -234,27 +228,27 @@ public function createAnonymousUser(): UserRecord
return $this->createUser(CreateUser::new());
}

public function changeUserPassword(Stringable|string $uid, Stringable|string $newPassword): UserRecord
public function changeUserPassword(string $uid, string $newPassword): UserRecord
{
return $this->updateUser($uid, UpdateUser::new()->withClearTextPassword($newPassword));
}

public function changeUserEmail(Stringable|string $uid, Stringable|string $newEmail): UserRecord
public function changeUserEmail(string $uid, string $newEmail): UserRecord
{
return $this->updateUser($uid, UpdateUser::new()->withEmail($newEmail));
}

public function enableUser(Stringable|string $uid): UserRecord
public function enableUser(string $uid): UserRecord
{
return $this->updateUser($uid, UpdateUser::new()->markAsEnabled());
}

public function disableUser(Stringable|string $uid): UserRecord
public function disableUser(string $uid): UserRecord
{
return $this->updateUser($uid, UpdateUser::new()->markAsDisabled());
}

public function deleteUser(Stringable|string $uid): void
public function deleteUser(string $uid): void
{
$uid = Uid::fromString($uid)->value;

Expand All @@ -277,9 +271,9 @@ public function deleteUsers(iterable $uids, bool $forceDeleteEnabledUsers = fals
return DeleteUsersResult::fromRequestAndResponse($request, $response);
}

public function getEmailActionLink(string $type, Stringable|string $email, $actionCodeSettings = null, ?string $locale = null): string
public function getEmailActionLink(string $type, string $email, $actionCodeSettings = null, ?string $locale = null): string
{
$email = Email::fromString((string) $email)->value;
$email = Email::fromString($email)->value;

if ($actionCodeSettings === null) {
$actionCodeSettings = ValidatedActionCodeSettings::empty();
Expand All @@ -292,9 +286,9 @@ public function getEmailActionLink(string $type, Stringable|string $email, $acti
return $this->client->getEmailActionLink($type, $email, $actionCodeSettings, $locale);
}

public function sendEmailActionLink(string $type, Stringable|string $email, $actionCodeSettings = null, ?string $locale = null): void
public function sendEmailActionLink(string $type, string $email, $actionCodeSettings = null, ?string $locale = null): void
{
$email = Email::fromString((string) $email)->value;
$email = Email::fromString($email)->value;

if ($actionCodeSettings === null) {
$actionCodeSettings = ValidatedActionCodeSettings::empty();
Expand Down Expand Up @@ -330,45 +324,45 @@ public function sendEmailActionLink(string $type, Stringable|string $email, $act
$this->client->sendEmailActionLink($type, $email, $actionCodeSettings, $locale, $idToken);
}

public function getEmailVerificationLink(Stringable|string $email, $actionCodeSettings = null, ?string $locale = null): string
public function getEmailVerificationLink(string $email, $actionCodeSettings = null, ?string $locale = null): string
{
return $this->getEmailActionLink('VERIFY_EMAIL', $email, $actionCodeSettings, $locale);
}

public function sendEmailVerificationLink(Stringable|string $email, $actionCodeSettings = null, ?string $locale = null): void
public function sendEmailVerificationLink(string $email, $actionCodeSettings = null, ?string $locale = null): void
{
$this->sendEmailActionLink('VERIFY_EMAIL', $email, $actionCodeSettings, $locale);
}

public function getPasswordResetLink(Stringable|string $email, $actionCodeSettings = null, ?string $locale = null): string
public function getPasswordResetLink(string $email, $actionCodeSettings = null, ?string $locale = null): string
{
return $this->getEmailActionLink('PASSWORD_RESET', $email, $actionCodeSettings, $locale);
}

public function sendPasswordResetLink(Stringable|string $email, $actionCodeSettings = null, ?string $locale = null): void
public function sendPasswordResetLink(string $email, $actionCodeSettings = null, ?string $locale = null): void
{
$this->sendEmailActionLink('PASSWORD_RESET', $email, $actionCodeSettings, $locale);
}

public function getSignInWithEmailLink(Stringable|string $email, $actionCodeSettings = null, ?string $locale = null): string
public function getSignInWithEmailLink(string $email, $actionCodeSettings = null, ?string $locale = null): string
{
return $this->getEmailActionLink('EMAIL_SIGNIN', $email, $actionCodeSettings, $locale);
}

public function sendSignInWithEmailLink(Stringable|string $email, $actionCodeSettings = null, ?string $locale = null): void
public function sendSignInWithEmailLink(string $email, $actionCodeSettings = null, ?string $locale = null): void
{
$this->sendEmailActionLink('EMAIL_SIGNIN', $email, $actionCodeSettings, $locale);
}

public function setCustomUserClaims(Stringable|string $uid, ?array $claims): void
public function setCustomUserClaims(string $uid, ?array $claims): void
{
$uid = Uid::fromString($uid)->value;
$claims ??= [];

$this->client->setCustomUserClaims($uid, $claims);
}

public function createCustomToken(Stringable|string $uid, array $claims = [], $ttl = 3600): UnencryptedToken
public function createCustomToken(string $uid, array $claims = [], $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 @@ -507,7 +501,7 @@ public function confirmPasswordReset(string $oobCode, $newPassword, bool $invali
return $email;
}

public function revokeRefreshTokens(Stringable|string $uid): void
public function revokeRefreshTokens(string $uid): void
{
$uid = Uid::fromString($uid)->value;

Expand All @@ -518,12 +512,7 @@ public function unlinkProvider($uid, $provider): UserRecord
{
$uid = Uid::fromString($uid)->value;

$provider = array_values(
array_filter(
array_map(strval(...), (array) $provider),
static fn(string $value): bool => $value !== '',
),
);
$provider = array_map(strval(...), (array) $provider);
Copy link

Copilot AI Dec 5, 2025

Choose a reason for hiding this comment

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

Missing validation to filter out empty strings from providers. The old implementation used array_filter() to remove empty strings before passing to the API client, which expects list<non-empty-string>. Now the code only converts to strings with array_map(strval(...), (array) $provider) but doesn't filter empty strings.

Consider restoring the filter:

$provider = array_values(
    array_filter(
        array_map(strval(...), (array) $provider),
        static fn(string $value): bool => $value !== '',
    ),
);
Suggested change
$provider = array_map(strval(...), (array) $provider);
$provider = array_values(
array_filter(
array_map(strval(...), (array) $provider),
static fn(string $value): bool => $value !== '',
),
);

Copilot uses AI. Check for mistakes.

$response = $this->client->unlinkProvider($uid, $provider);

Expand All @@ -533,7 +522,7 @@ public function unlinkProvider($uid, $provider): UserRecord
public function signInAsUser($user, ?array $claims = null): SignInResult
{
$claims ??= [];
$uid = $user instanceof UserRecord ? $user->uid : (string) $user;
$uid = $user instanceof UserRecord ? $user->uid : $user;

try {
$customToken = $this->createCustomToken($uid, $claims);
Expand All @@ -560,15 +549,15 @@ public function signInWithRefreshToken(string $refreshToken): SignInResult

public function signInWithEmailAndPassword($email, $clearTextPassword): SignInResult
Copy link

Copilot AI Dec 5, 2025

Choose a reason for hiding this comment

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

Missing string type hints for parameters. The interface Auth declares this method as signInWithEmailAndPassword(string $email, string $clearTextPassword) (line 424), but the implementation is missing type hints for both parameters. These should be explicitly typed as string to match the interface and align with the PR's goal of replacing Stringable|string with string.

Suggested change
public function signInWithEmailAndPassword($email, $clearTextPassword): SignInResult
public function signInWithEmailAndPassword(string $email, string $clearTextPassword): SignInResult

Copilot uses AI. Check for mistakes.
{
$email = Email::fromString((string) $email)->value;
$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
Copy link

Copilot AI Dec 5, 2025

Choose a reason for hiding this comment

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

Missing string type hint for $email parameter. The interface Auth declares this method as signInWithEmailAndOobCode(string $email, string $oobCode) (line 432), but the implementation is missing the type hint for $email. It should be explicitly typed as string to match the interface and align with the PR's goal.

Suggested change
public function signInWithEmailAndOobCode($email, string $oobCode): SignInResult
public function signInWithEmailAndOobCode(string $email, string $oobCode): SignInResult

Copilot uses AI. Check for mistakes.
{
$email = Email::fromString((string) $email)->value;
$email = Email::fromString($email)->value;

return $this->client->handleSignIn(SignInWithEmailAndOobCode::fromValues($email, $oobCode));
}
Expand All @@ -591,7 +580,6 @@ public function signInAnonymously(): SignInResult

public function signInWithIdpAccessToken($provider, string $accessToken, $redirectUrl = null, ?string $oauthTokenSecret = null, ?string $linkingIdToken = null, ?string $rawNonce = null): SignInResult
Copy link

Copilot AI Dec 5, 2025

Choose a reason for hiding this comment

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

Missing string type hint for $provider parameter. The interface Auth declares this method with string $provider (line 451), but the implementation is missing the type hint. It should be explicitly typed as string to match the interface and align with the PR's goal of removing Stringable support.

Suggested change
public function signInWithIdpAccessToken($provider, string $accessToken, $redirectUrl = null, ?string $oauthTokenSecret = null, ?string $linkingIdToken = null, ?string $rawNonce = null): SignInResult
public function signInWithIdpAccessToken(string $provider, string $accessToken, $redirectUrl = null, ?string $oauthTokenSecret = null, ?string $linkingIdToken = null, ?string $rawNonce = null): SignInResult

Copilot uses AI. Check for mistakes.
{
$provider = (string) $provider;
$redirectUrl = trim((string) ($redirectUrl ?? 'http://localhost'));
$linkingIdToken = trim((string) $linkingIdToken);
$oauthTokenSecret = trim((string) $oauthTokenSecret);
Expand Down Expand Up @@ -620,7 +608,6 @@ public function signInWithIdpAccessToken($provider, string $accessToken, $redire

public function signInWithIdpIdToken($provider, $idToken, $redirectUrl = null, ?string $linkingIdToken = null, ?string $rawNonce = null): SignInResult
Copy link

Copilot AI Dec 5, 2025

Choose a reason for hiding this comment

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

Missing string type hint for $provider parameter. The interface Auth declares this method with string $provider (line 462), but the implementation is missing the type hint. It should be explicitly typed as string to match the interface and align with the PR's goal of removing Stringable support.

Suggested change
public function signInWithIdpIdToken($provider, $idToken, $redirectUrl = null, ?string $linkingIdToken = null, ?string $rawNonce = null): SignInResult
public function signInWithIdpIdToken(string $provider, $idToken, $redirectUrl = null, ?string $linkingIdToken = null, ?string $rawNonce = null): SignInResult

Copilot uses AI. Check for mistakes.
{
$provider = trim((string) $provider);
$redirectUrl = trim((string) ($redirectUrl ?? 'http://localhost'));
$linkingIdToken = trim((string) $linkingIdToken);
$rawNonce = trim((string) $rawNonce);
Expand Down
3 changes: 1 addition & 2 deletions src/Firebase/Auth/ApiClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
use Kreait\Firebase\Request\UpdateUser;
use Psr\Clock\ClockInterface;
use Psr\Http\Message\ResponseInterface;
use Stringable;
use Throwable;

use function array_filter;
Expand Down Expand Up @@ -239,7 +238,7 @@ public function revokeRefreshTokens(string $uid): ResponseInterface
}

/**
* @param list<Stringable|non-empty-string> $providers
* @param list<non-empty-string> $providers
*
* @throws AuthException
*/
Expand Down
5 changes: 2 additions & 3 deletions src/Firebase/Auth/CreateActionLink.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
namespace Kreait\Firebase\Auth;

use Kreait\Firebase\Value\Email;
use Stringable;

/**
* @internal
Expand All @@ -21,9 +20,9 @@ private function __construct(
) {
}

public static function new(string $type, Stringable|string $email, ActionCodeSettings $settings, ?string $tenantId = null, ?string $locale = null): self
public static function new(string $type, string $email, ActionCodeSettings $settings, ?string $tenantId = null, ?string $locale = null): self
{
$email = Email::fromString((string) $email)->value;
$email = Email::fromString($email)->value;

return new self($tenantId, $locale, $type, $email, $settings);
}
Expand Down
9 changes: 5 additions & 4 deletions src/Firebase/Auth/CustomTokenViaGoogleCredentials.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
use Lcobucci\JWT\Encoding\JoseEncoder;
use Lcobucci\JWT\Token;
use Lcobucci\JWT\Token\Parser;
use Stringable;

/**
* @internal
Expand All @@ -31,13 +30,15 @@ public function __construct(private SignBlobInterface $signer, private ?string $
}

/**
* @param Stringable|string $uid
* @param non-empty-string $uid
* @param array<non-empty-string, mixed> $claims
*
* @throws AuthError
*/
public function createCustomToken($uid, array $claims = [], ?DateTimeInterface $expiresAt = null): Token
public function createCustomToken(string $uid, ?array $claims = null, ?DateTimeInterface $expiresAt = null): Token
{
$claims ??= [];

$now = new DateTimeImmutable();
$expiresAt = ($expiresAt !== null)
? DT::toUTCDateTimeImmutable($expiresAt)
Expand All @@ -50,7 +51,7 @@ public function createCustomToken($uid, array $claims = [], ?DateTimeInterface $
'aud' => 'https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit',
'iat' => $now->getTimestamp(),
'exp' => $expiresAt->getTimestamp(),
'uid' => (string) $uid,
'uid' => $uid,
];

if ($this->tenantId !== null) {
Expand Down
3 changes: 1 addition & 2 deletions src/Firebase/Auth/DeleteUsersRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

use Kreait\Firebase\Exception\InvalidArgumentException;
use Kreait\Firebase\Value\Uid;
use Stringable;

/**
* @internal
Expand All @@ -23,7 +22,7 @@ private function __construct(
}

/**
* @param iterable<Stringable|string> $uids
* @param iterable<string> $uids
*/
public static function withUids(iterable $uids, bool $forceDeleteEnabledUsers = false): self
{
Expand Down
Loading
Loading