Обновление токена Laravel Socialite

access_token, приобретенный Socialite (через Socialite::driver(self::PROVIDER)->user()), имеет ограниченный срок действия. Для Google это час.

Я могу получить refresh_token, изменив вызов перенаправления на:

Socialite::driver(self::PROVIDER)->stateless()->with([
    'access_type' => 'offline',
])->redirect()

В течение часа я могу читать пользовательские данные на основе access_token, вызывая

// $token = read_stored_access_token()
\Socialite::driver(self::PROVIDER)->userFromToken($accessToken);

Через час, когда токен становится недействительным, Google API начинает возвращать 401 Unauthorized, и Socialize распространяет это:

(1/1) ClientException
Client error: `GET https://www.googleapis.com/plus/v1/people/me?prettyPrint=false` resulted in a `401 Unauthorized` response:
{"error":{"errors":[{"domain":"global","reason":"authError","message":"Invalid Credentials","locationType":"header","loc (truncated...)

Теперь с refresh_token я смогу легко обновить access_token. Но я не могу найти упоминания в документации или исходном коде Socialize, которые позволили бы мне это сделать.

Действительно ли единственный способ сделать это - использовать библиотеку API Google и сделать это вручную? Разве это не убивает всю идею использования Socialize?

Примечание. Я стараюсь не звонить redirect() снова, так как это может заставить пользователя каждый час выбирать одну из своих учетных записей Google, что раздражает.

Спасибо!


person rootpd    schedule 11.07.2017    source источник
comment
И дополнительный вопрос: какой смысл предоставлять доступ к refresh_token, если его нельзя использовать дальше без реализации собственного клиента вручную?   -  person rootpd    schedule 14.07.2017


Ответы (2)


Вот как я спасаю пользователя от Socialize с автономным доступом:

            $newUser                       = new User;
            $newUser->name                 = $user->name;
            $newUser->email                = $user->email;
            $newUser->google_id            = $user->id;
            $newUser->google_token         = $user->token;
            $newUser->token_expires_at     = Carbon::now()->addSeconds($user->expiresIn);
            $newUser->google_refresh_token = $user->refreshToken;
            $newUser->avatar               = $user->avatar;
            $newUser->avatar_original      = $user->avatar_original;
            $newUser->save();

И вот мое решение для обновления токена. Я сделал это, создав аксессор для атрибута токена в моей модели пользователя:

    /**
     * Accessor for google token of the user
     * Need for token refreshing when it has expired
     *
     * @param $token
     *
     * @return string
     */
    public function getGoogleTokenAttribute( $token ) {
        //Checking if the token has expired
        if (Carbon::now()->gt(Carbon::parse($this->token_expires_at))) {
            $url  = "https://www.googleapis.com/oauth2/v4/token";
            $data = [
                "client_id"     => config('services.google.client_id'),
                "client_secret" => config('services.google.client_secret'),
                "refresh_token" => $this->google_refresh_token,
                "grant_type"    => 'refresh_token'
            ];

            $ch = curl_init($url);

            curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/x-www-form-urlencoded']);
            curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
            curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
            $result = curl_exec($ch);
            $err    = curl_error($ch);

            curl_close($ch);

            if ($err) {
                return $token;
            }
            $result = json_decode($result, true);

            $this->google_token     = isset($result['access_token']) ? $result['access_token'] : "need_to_refresh";
            $this->token_expires_at = isset($result['expires_in']) ? Carbon::now()->addSeconds($result['expires_in']) : Carbon::now();
            $this->save();

            return $this->google_token;

        }

        return $token;
    }
person Arm092    schedule 10.12.2019

return Socialite::driver('google')
    ->scopes() 
    ->with(["access_type" => "offline", "prompt" => "consent select_account"])
    ->redirect();

По умолчанию refresh_token возвращается только при первой авторизации, добавив «prompt» => «consent select_account» мы заставляем его возвращаться каждый раз.

person Saifullah khan    schedule 20.08.2018