Laravel Socialite token refreshing
Here is the way I saving user from Socialite with offline access:
$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();
And here is my solution for token refreshing. I made it via creating accessor for token attribute in my User model:
/** * 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; }
return Socialite::driver('google') ->scopes() ->with(["access_type" => "offline", "prompt" => "consent select_account"]) ->redirect();
By default refresh_token is returned only on first authorization, by adding "prompt" => "consent select_account" we force it to be returned every time.