# Introduction

THE social authentication solution for Laravel Breeze, Jetstream and Filament Admin Panels.

## What is Socialstream?

Socialstream is a third-party Laravel package, delivering an all encompassing solution to adding social OAuth integration to your Laravel Jetstream, Laravel Breeze, or Filament Admin Panel based Laravel application.

With Socialstream, you no longer need to spend hours designing the business logic behind social OAuth for your users, simply install the package for your desired starter kit and supported stack, run your migrations, set your supported providers in `./config/socialstream.php` and configure their client details in `./config/services.php`. Finally, build your frontend and set the desired features (such as [global login](/features/global-login), or [generate missing emails](/features/missing-emails)) and off you go!

When installed, it provides a UI adaptation on top of all three technologies to provide support for all the first-party social providers supported by Laravel Socialite out-of-the-box. For clarity, Socialstream explicitly provides support for:

* Bitbucket
* Facebook
* Github
* Gitlab
* Google
* LinkedIn
* LinkedIn (via OpenId)
* Slack
* Twitter

{% hint style="info" %}
Further integration with other providers (such as Apple, Microsoft, Reddit and many more) can be added by using the [Socialite Providers](https://github.com/socialiteproviders) package. A guide on how to do this can be found [here](/guides/socialite-providers).
{% endhint %}

When you first install Socialstream into your application, via the `socialstream:install` artisan command, you will be guided through the installation specific for your application. You will be asked a series of questions, such as which starter kit you will be using and the associated technology stack that powers it (e.g. Laravel Jetstream and Livewire, or Laravel Breeze and Volt's functional API).

{% hint style="warning" %}
Socialstream is designed to work in tandem with either of Laravel's starter kits (Breeze and Jetstream) and Filament Admin Panel, and as such, Socialstream should be installed into a **NEW** Laravel applications only. **It is not recommended to install Socialstream into an existing application**
{% endhint %}

## How does it work?

Under the hood, Socialstream harnesses the power of Laravel Socialite to power each OAuth integration. When you add Socialstream to your project (via `composer require`) it will automatically pull in the latest compatible version of Laravel Socialite for you, so you don't have to remember to install it yourself!

Socialstream exposes two wildcard routes. The first is `/oauth/{provider}`  (`oauth.redirect`). This route should be called by any "Log in Via \[X]" button on your site or in your application and will redirect your user(s) to the providers OAuth flow.

The second route is is `/oauth/{provider}/callback`  (`oauth.callback`). This is the callback URL that each provider will send your user(s) once they have completed their OAuth authorization.

{% hint style="info" %}
You will not need to add these routes to your routes files, nor will you need to publish any routes files for them to work.
{% endhint %}

## What does it provide?

### Frontend

Depending on the starter kit and stack you are using, Socialstream will configure the published view files for Laravel Jetstream or Laravel Breeze to add a section beneath the login / registration panels that users can click for each of your applications supported browsers. The frontend logic can be found in the following published files:

* Laravel Jetstream (Livewire) – `socialstream.blade.php`
* Laravel Jetstream (Inertia) – `Socialstream.vue`
* Laravel Breeze (blade, livewire, livewire-functional) – `socialstream.blade.php`
* Laravel Breeze (vue, vue typescript) – `Socialstream.vue`
* Laravel Breeze (react) – `Socialstream.jsx`,&#x20;
* Laravel Breeze (react typescript) – `Socialstream.jsx`

### Backend

Installing Socialstream will publish four different things for the backend.

#### Config

The first is a config file, this will be published to `./config/socialstream.php`. This config file controls a number of things from the middleware used to wrap Socialstreams routes, to the enabled providers, the enabled features and, in the case of Filament, the auth guard and component used to render Socialstream's UI.

#### Migrations & Models

The second is some migrations and their relevant models. The migrations are to adjust the users table so the password can be set to `null` and another migration to create the `connected_accounts` table (one user can have many linked accounts). The models are `User` and `ConnectedAccount`.&#x20;

#### Actions

The third is a bunch of "Action" classes (located at `/app/Actions/Socialstream`) used by Socialstream to execute various features. The published actions include:

* `CreateConnectedAccount`
* `CreateNewUserFromProvider`
* `GenerateRedirectForProvider`
* `HandleInvalidState`
* `ResolveSocialiteUser`
* `SetUserPassword`
* `UpdateConnectedAccount`

#### Service Provider

The fourth thing published for the backend, is the `SocialstreamServiceProvider`. This configures a bunch of sensible defaults for Socialstream's actions, and sets the base models used by Socialstream to the ones that are published along with the migrations.


# Release Notes

## Versioning Scheme

Socialstream follows [Semantic Versioning](https://semver.org/). We try to keep breaking changes to a minimum. However, major releases may contain breaking change, or in some circumstance, rewrite entire parts of the packages inner-workings. Miner and patch releases should **never** contain breaking changes.

## Laravel

Socialstream major versions follow the latest major Laravel version. At its release, Socialstream 6.x requires Laravel 11.

## PHP

Socialstream follows the minimum required Laravel PHP version. At its release, Socialstream 6.x requires a minimum PHP version of 8.2.


# Upgrade Guide

## Overview

* [Upgrading to v5 from 4.x](/prologue/upgrade-guide/upgrading-to-v5-from-4.x)
* [Upgrading to v4 from 3.x](/prologue/upgrade-guide/upgrading-to-v4-from-3.x)
* [Upgrading to v3 from 2.x](/prologue/upgrade-guide/upgrading-to-v3-from-2.x)
* [Upgrading to v2 from 1.x](/prologue/upgrade-guide/upgrading-to-v2-from-1.x)


# Upgrading to v6 from 5.x

{% hint style="info" %}
A Laravel 11 demo repo can be found [here](https://github.com/joelbutcher/socialstream-demo). This repo was originally built with Laravel 10 and Jetstream v4 with Vue for Inertia for the frontend. To view the complete upgrade to Laravel 11, check out this [merge commit](https://github.com/joelbutcher/socialstream-demo/commit/903934d233038f2034f90d4bca78f4c433349463).
{% endhint %}

## Updating Dependencies

### **PHP 8.2.0 Required**

Socialstream now requires PHP 8.2.0 or higher

### Laravel 11 Required

Socialstream new requires Laravel 11 to be installed, to do update the `laravel/framework` composer dependency to `^11.0` in your application's `composer.json` file.

{% hint style="warning" %}
Please follow the [official upgrade guide](https://laravel.com/docs/11.x/upgrade#upgrade-11.0) on what dependencies also need updating for this
{% endhint %}

### Jetstream 5 Required

If you use Socialstream with Laravel Jetstream, please ensure you have followed the [official upgrade guide](https://github.com/laravel/jetstream/blob/5.x/UPGRADE.md) for upgrading you Jetstream version to v5

### Filament

If you use Socialstream along with Filament Admin Panels, you will want to make sure you've upgraded `filament/filament` to `v3.2.39`


# Upgrading to v5 from 4.x

{% hint style="info" %}
This upgrade guide only discusses upgrading Socialstream 5.x and assumes you are upgrading from an **unaltered 4.x install**. Upgrading Jetstream, Livewire, Inertia, Vue or Tailwind CSS is out of scope for this documentation. Please consult the upgrade guides for each of these packages instead.
{% endhint %}

## Overview

* [Upgrading via `socialstream:upgrade`](#upgrading-via-socialstream-upgrade)
* [Upgrading Manually](#upgrading-manually)
  * [Updating Dependencies](#updating-dependencies)
  * [Renaming Oauth to OAuth](#renaming-oauth-to-oauth)
  * [The `Socialstream::refresesOauthTokens` Method](#the-socialstream-refresesoauthtokens-method)
  * [The `Socialstream` component](#the-socialstream-component)
  * [The `Socialstream::providers` Method](#the-socialstream-providers-method)
    * [Livewire Stack Changes](#livewire-stack-changes)
    * [Inertia Stack Changes](#inertia-changes)
  * [The `HandlesInvalidState::handle` method](#the-handlesinvalidstate-handle-method)

***

## Upgrading via `socialstream:upgrade`

{% hint style="info" %}
The `socialstream:upgrade` artisan command is only available **after** installing Socialstream `5.0` and assumes you have an **unaltered** `4.x` install.
{% endhint %}

Upgrading Socialstream has never been easier. With `5.0` we have created an artisan command that will guide you through all the changes you need to make. Simply execute the following command:

```sh
php artisan socialstream:upgrade
```

You may then follow the on-screen instructions to complete the upgrade to Socialstream 5.0.

***

## Upgrading Manually

### Updating Dependencies

{% hint style="danger" %}
Impact: **High**
{% endhint %}

Socialstream v5.0 removes `laravel/jetstream` as a dependency due to adding support for multiple stater kit options. Before upgrading, you should ensure that jetstream is added to the `require` dependencies your `composer.json` file. You can do this by executing the following command:

```sh
composer require laravel/jetstream:
```

### Renaming Oauth to OAuth

{% hint style="danger" %}
Impact: **High**
{% endhint %}

v5 applies a patch to rename all incorrect instances of "Oauth" with "OAuth". Please make sure you have updated any usages to also match this change.

### The `Socialstream::refresesOauthTokens` Method

{% hint style="danger" %}
Impact: **High**
{% endhint %}

This method has been renamed to fix the typo, if you are using the method, please update it to `refreshesOAuthTokens`.

### The `Socialstream` Component

{% hint style="warning" %}
Impact: **Medium**
{% endhint %}

The main `Socialstream` component has been updated, you should replace it's contents with the one found on GitHub for your chosen Jetstream stack:

* [Livewire](https://github.com/joelbutcher/socialstream/blob/18f0990f3c51b22271d7edb2a40e0afdd3d40fdf/stubs/jetstream/livewire/resources/views/components/socialstream.blade.php)
* [Inertia](https://github.com/joelbutcher/socialstream/blob/18f0990f3c51b22271d7edb2a40e0afdd3d40fdf/stubs/jetstream/inertia/resources/js/Components/Socialstream.vue)

### Provider Icons

{% hint style="warning" %}
Impact: **Medium**
{% endhint %}

The new default installation for Socialstream moves the logic for showing a providers icon to it's own component for each stack. It is recommended that you copy this logic over for your stack and update your existing Socialstream installation to reference the new component:

**Livewire**

Create a new `provider-icon.blade.php` within `resources/views/components/socialstream-icons` inside your Laravel Application and add the contents from [here](https://github.com/joelbutcher/socialstream/blob/bb100b8d6f5f2cc046b61f845b92ba9c5fa64fcf/stubs/jetstream/livewire/resources/views/components/socialstream-icons/provider-icon.blade.php), making sure to cater for any additional icons you may have added.

Replace any `@if`, `@elseif` and `@else` directive calls that are used to determine what icons are shown with:

```php
<x-socialstream-icons.provider-icon :provider="$provider['id']" class="h-6 w-6"/>
```

### The `Socialstream::providers` Method

{% hint style="danger" %}
Impact: **High**
{% endhint %}

The `Socialstream::providers` method now returns an array of arrays for each registered provider. The data structure for providers is built using `JoelButcher\Socialstream\Data\ProviderData::toArray` and looks like the following example:

```
[
    'id' => 'github',
    'name' => 'GitHub',
    'buttonLabel' => 'GitHub', // configurable, can also be null.
]
```

#### **Livewire Stack Changes**

**Add a new `provider-icon.blade.php` Component**

This new component is a switch-case around the `$provider['id']` property and used to determine which icon should be shown. You should place this component within the `resources/views/components/socialstream-icons` directory of your Laravel application. The source code can be found [here](https://github.com/joelbutcher/socialstream/blob/5.x/stubs/jetstream/livewire/resources/views/components/socialstream-icons/provider-icon.blade.php).

{% hint style="info" %}
You will want to include the cases for any additional providers you may have added to your Socialstream installation.
{% endhint %}

This component is referenced within [`socialstream.blade.php` component](https://github.com/joelbutcher/socialstream/blob/18f0990f3c51b22271d7edb2a40e0afdd3d40fdf/stubs/jetstream/livewire/resources/views/components/socialstream.blade.php) and the [`connected-account.blade.php` component](https://github.com/joelbutcher/socialstream/blob/cbf0c55a4dbf2cef48edccf80b52115c69b205b1/stubs/jetstream/livewire/resources/views/components/connected-account.blade.php#L6C13-L6C95).

**Changes to `connected-account.blade.php`**

Socialstream `5.0` updates the `connected-account` component to use the new provider array. You should update your version of this component to match the source code's [expectations](https://github.com/joelbutcher/socialstream/blob/cbf0c55a4dbf2cef48edccf80b52115c69b205b1/stubs/jetstream/livewire/resources/views/components/connected-account.blade.php#L10).

You should also update your applications `connected-accounts-form.blade.php` to reflect the change to the `$provider` array:

```php
// Replace line 27
$account = $this->accounts->where('provider', $provider)->first();

// With
$account = $this->accounts->where('provider', $provider['id'])->first();

---

// Replace line 30
<x-connected-account provider="{{ $provider }}" created-at="{{ $account?->created_at }}">

// With
<x-connected-account :provider="$provider" created-at="{{ $account?->created_at }}">

---

// Replace line 47
<x-action-link href="{{ route('oauth.redirect', ['provider' => $provider]) }}">

// With
<x-action-link href="{{ route('oauth.redirect', ['provider' => $provider['id']]) }}">

---


// Replace line 72
<x-danger-button class="ml-2" wire:click="removeConnectedAccount({{ $this->selectedAccountId }})" wire:loading.attr="disabled">

// With
<x-danger-button class="ml-2" wire:click="removeConnectedAccount({{ $this->id }})" wire:loading.attr="disabled">
```

#### Inertia **Stack** Changes

**Add a new `ProviderIcon.vue` Component**

Socialstream 5.0 adds a new `ProviderIcon.vue` component. You will want to add this component from [GitHub](https://github.com/joelbutcher/socialstream/blob/24a99bb8a8d3a0dc2a3ee71e04e68768c65c6a27/stubs/jetstream/inertia/resources/js/Components/SocialstreamIcons/ProviderIcon.vue) and ensure any additional provider icons you have created are catered for.

This component is referenced within [`Socialstream.vue` ](https://github.com/joelbutcher/socialstream/blob/18f0990f3c51b22271d7edb2a40e0afdd3d40fdf/stubs/jetstream/livewire/resources/views/components/socialstream.blade.php)and [`ConnectedAccount.vue`](https://github.com/joelbutcher/socialstream/blob/cbf0c55a4dbf2cef48edccf80b52115c69b205b1/stubs/jetstream/livewire/resources/views/components/connected-account.blade.php#L6C13-L6C95).

**Changes to `ConnectedAccount.vue`**

The connected account component has been updated to reflect the changes made to the `Socialstream::providers` method. As a result, existing installations of this component will now break. You will want to make sure that your `ConnectedAccount.vue` component is updated to align with the [new version on GitHub](https://github.com/joelbutcher/socialstream/blob/24a99bb8a8d3a0dc2a3ee71e04e68768c65c6a27/stubs/jetstream/inertia/resources/js/Components/ConnectedAccount.vue).

**Changes to Auth Views**

Both `Login.vue` and `Register.vue` have been updated to pass properties from `$page.props.socialstream` into the updated `Socialstream.vue` component. Please make sure to review these changes and update your application accordingly.

**Changes to `ConnectedAccountsForm.vue` component**

A lot of the logic in this component has been updated to align with the changes made to `Socialstream::providers`, you may wish to review the [code on GitHub](https://github.com/joelbutcher/socialstream/blob/24a99bb8a8d3a0dc2a3ee71e04e68768c65c6a27/stubs/jetstream/inertia/resources/js/Pages/Profile/Partials/ConnectedAccountsForm.vue) and update your version of the component to ensure compatibility.

***

### The `HandlesInvalidState::handle` method

{% hint style="info" %}
Impact: **Low**
{% endhint %}

The `HandlesInvalidState` contract has been updated to remove the `$callback` parameter, this parameter was never used by Socialstream or called in anyway. You should update your implementations to also remove this parameter.


# Upgrading to v4 from 3.x

{% hint style="info" %}
This upgrade guide only discusses upgrading Socialstream 4.x and assumes you are upgrading from an **unaltered 3.x install**. Upgrading Jetstream, Livewire, Inertia, Vue or Tailwind CSS is out of scope for this documentation. Please consult the upgrade guides for each of these packages instead.
{% endhint %}

## Overview <a href="#user-content-changes" id="user-content-changes"></a>

* [Changes](#user-content-changes-1)
  * [Native Type Declarations](#user-content-changes-2)
  * [User Profile Photo](#user-profile-photo)
  * [Inertia Props](#changes-to-jetstream-props-in-inertia)

***

## Changes <a href="#user-content-changes" id="user-content-changes"></a>

### **Native Type declarations** <a href="#user-content-changes" id="user-content-changes"></a>

{% hint style="danger" %}
Impact: **High**
{% endhint %}

Version 4.x updates the interfaces and published `php` files to use native type declarations. Please ensure the following files have been updated to match their interface counterparts:

```
CreateConnectedAccount.php
CreateUserFromProvider.php
HandleInvalidState.php
ResolveSocialiteUser.php
SetUserPassword.php
UpdateConnectedAccount.php
```

### **User Profile Photo**

{% hint style="danger" %}
Impact: **High**
{% endhint %}

If you have included the `HasProfilePhoto` trait in your user model, please update your model to the following:

```diff
    use HasProfilePhoto {
-       getProfilePhotoUrlAttribute as getPhotoUrl;
+       HasProfilePhoto::profilePhotoUrl as getPhotoUrl;
    }
```

And replace the `getProfilePhotoUrlAttribute` method in the model with:

```php
/**
 * Get the URL to the user's profile photo.
 */
public function profilePhotoUrl(): Attribute
{
    return filter_var($this->profile_photo_path, FILTER_VALIDATE_URL)
        ? Attribute::get(fn () => $this->profile_photo_path)
        : $this->getPhotoUrl();
}
```

### **Inertia Props**

{% hint style="danger" %}
Impact: **High**
{% endhint %}

If you're using Inertia, please update your `Profile/Show.vue` file to the following:

```diff
-29:                    <UpdateProfileInformationForm :user="$page.props.user" />
+29:                    <UpdateProfileInformationForm :user="$page.props.auth.user" />
```


# Upgrading to v3 from 2.x

{% hint style="info" %}
This upgrade guide only discusses upgrading Socialstream 3.x and assumes you are upgrading from an **unaltered 2.x install**. Upgrading Jetstream, Livewire, Inertia, Vue or Tailwind CSS is out of scope for this documentation. Please consult the upgrade guides for each of these packages instead.
{% endhint %}

## Overview <a href="#user-content-changes-1" id="user-content-changes-1"></a>

* [Changes](#user-content-changes-1-1)
  * [Disabling Socialstream](#disabling-socialstream)
  * [Providers](#providers)
  * [Remember Sessions](#remember-sessions)
  * [Token Column Length](#token-column-lengths)
  * [Provider Avatars](#provider-avatars)
  * [Connected Account Policy](#connected-account-policy)
  * [Updating Connected Accounts](#updating-connected-accounts)
  * [Resolving Users from Socialite](#resolving-users-from-socialite)

***

## Changes <a href="#user-content-changes-1" id="user-content-changes-1"></a>

### Disabling Socialstream

{% hint style="info" %}
Impact: **Low**
{% endhint %}

To disable Socialstream in v3, you will need to update your existing `SocialstreamServiceProvider.php` to include the following code snippet in your providers `boot` method:

```php
Socialstream::enabled(fn () => false);
```

The function accepts a callback so if you wanted to implement more complex logic, you may do so.

> Note, the callback MUST return a boolean

### Providers

{% hint style="info" %}
Impact: **Low**
{% endhint %}

V3 introduces a new `Providers` class, for defining what Socialite providers you have enabled in your config. This class is also used in the socialstream.blade.php stub and the connected-account.blade.php component stub. Please update any Socialite providers you have in your `socialstream.php` config file to use this class, e.g:

```php
use \JoelButcher\Socialstream\Providers;

return [
    // ...

    'providers' => [
        Providers::google(),
        Providers::facebook(),
    ],

];
```

### Remember Sessions

{% hint style="info" %}
Impact: **Low**
{% endhint %}

V3 of Socialstream move the remember session config variable into the 'features' config array. During your upgrade, if you have previously set this config variable to `true`, you will need to add it to your features list.

```php
return [
    // ...

    'features' => [
        Features::rememberSession(),
    ],

];
```

### Token Column Lengths

{% hint style="info" %}
Impact: **Low**
{% endhint %}

In version 3.x, we've fixed an issue with the length of tokens and refresh tokens being too long for the columns in the database.

To fix this yourself, you should create a new `connected_accounts` migration:

```sh
php artisan make:migration update_connected_accounts_token_lengths --table=connected_accounts
```

Once done, you should then add the following code to the `up` method:

```php
$table->string('token', 1000)->change();
$table->string('refresh_token', 1000)->change();
```

### Provider Avatars

{% hint style="info" %}
Impact: **Low**
{% endhint %}

In v3, we've updated the provider avatars feature to download the avatar from the url provided by the Socialite user. If you have opted to use the `providerAvatars` feature in your config's features definition, you should add the `SetsProfilePhotoFromUrl` trait to your user model:

```php
<?php

use JoelButcher\Socialstream\SetsProfilePhotoFromUrl;

class User extends Authenticatable
{
    // ...
    use SetsProfilePhotoFromUrl;

    // ...
}
```

It's worth noting that if you still to load the users profile photo from a URL, you will need to keep the `getProfilePhotoUrlAttribute` method override published by Socialstream, in your user model.

### Connected Account Policy

{% hint style="info" %}
Impact: **Low**
{% endhint %}

V3 uses a new policy to determine whether or not a user can access certain functionality. To ensure compatibility with v3, make sure you copy the stub found [here](https://github.com/joelbutcher/socialstream/blob/3.x/stubs/app/Policies/ConnectedAccountPolicy.php) to your `app/Policies` directory.

### Updating Connected Accounts

{% hint style="info" %}
Impact: **Low**
{% endhint %}

Socialstream v3 will now keep your connected accounts up to date whenever a user uses SSO with your application. updating a users OAuth token and refresh token on every successful login. To make sure this works for you, copy [this stub](https://github.com/joelbutcher/socialstream/blob/3.x/stubs/app/Actions/Socialstream/UpdateConnectedAccount.php) into the `app/Actions/Socialstream` directory. You will then need to add the following to your `app\Providers\SocialstreamServiceProvider.php`:

```php
use App\Actions\Socialstream\UpdateConnectedAccount;
use JoelButcher\Socialstream\Socialstream;

// Add this to the 'boot' method.
Socialstream::updateConnectedAccountsUsing(UpdateConnectedAccount::class);
```

### Resolving Users from Socialite

{% hint style="info" %}
Impact: **Low**
{% endhint %}

To allow additional flexibility, v3 allows you to override how your app resolves users from Socialite. For example, you may wish to call the `stateless` method, like so:

```php
$user = Socialite::driver('facebook')->stateless()->user();
```

To ensure v3 compatibility, copy the `ResolveSocialiteUser` action stub found [here](https://github.com/joelbutcher/socialstream/blob/3.x/stubs/app/Actions/Socialstream/ResolveSocialiteUser.php) to your `app/Actions/Socialstream` directory and add the following to your `app\Providers\SocialstreamServiceProvider.php`:

```php
use App\Actions\Socialstream\ResolveSocialiteUser;
use JoelButcher\Socialstream\Socialstream;

// Add this to the 'boot' method.
Socialstream::resolvesSocialiteUsersUsing(ResolveSocialiteUser::class);
```


# Upgrading to v2 from 1.x

{% hint style="info" %}
This upgrade guide only discusses upgrading Socialstream 2.x and assumes you are upgrading from an **unaltered 1.x install**. Upgrading Jetstream, Livewire, Inertia, Vue or Tailwind CSS is out of scope for this documentation. Please consult the upgrade guides for each of these packages instead.
{% endhint %}

## Overview

* [Changes](#user-content-changes-2)
  * [Connected Account Details](#connected-account-details)
  * [Current Connected Account Context](#current-connected-account-context)
  * [Create Connected Account Action](#create-connected-account-action)
  * [Generate Provider Redirect Action](#generate-provider-redirect-action)
  * [Connected Account Credentials](#user-content-connected-account-credentials)
  * [Inertia Stack Changes](#user-content-inertia-stack)
    * [Authentication Views](#authentication-views)

***

## Changes <a href="#user-content-changes-2" id="user-content-changes-2"></a>

### Connected Account Details

{% hint style="danger" %}
Impact: **High**
{% endhint %}

Version 2.x of Socialstream now captures more user data from a provider and saves them to your `connected_accounts` table. In order to correctly save this data, you will need to create a new migration to make the appropriate changes.

To do this, you should create a new `connected_accounts` migration:

```sh
php artisan make:migration update_connected_accounts_table --table=connected_accounts
```

The geneated migration should contain the following code:

```php
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class UpdateConnectedAccountsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('connected_accounts', function (Blueprint $table) {
            $table->string('name')->after('provider_name')->nullable();
            $table->string('nickname')->after('name')->nullable();
            $table->string('email')->after('nickname')->nullable();
            $table->string('telephone')->after('email')->nullable();
            $table->string('avatar_path')->after('telephone')->nullable();

            $table->renameColumn('provider_name', 'provider');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('connected_accounts', function (Blueprint $table) {
            // Revert...
        });
    }
}
```

### Current Connected Account Context

{% hint style="danger" %}
Impact: **High**
{% endhint %}

When you login using a social provider, Socialstream will now set the context for the most-recent, or "current" provider being used. To do this, a new `current_connected_account_id` column will need adding to your users table.

Generate a new `users` migration:

```sh
php artisan make:migration update_users_table --table=users
```

The migration should be popuplated with the following content:

```php
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class UpdateUsersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->foreignId('current_connected_account_id')->after('current_team_id')->nullable();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('users', function (Blueprint $table) {
            //
        });
    }
}
```

### Create Connected Account Action

{% hint style="danger" %}
Impact: **High**
{% endhint %}

Socialstream 2.x adds a new action for creating connected accounts on registration with a provider. You should copy the new [CreateConnectedAccount](https://github.com/joelbutcher/socialstream/blob/2.x/stubs/app/Actions/Socialstream/CreateConnectedAccount.php) action to the `App/Actions/Socialstream` directory in your project.

You should then add the register the action with Socialstream by placing the following code into the `boot` method of your application's `SocialstreamServiceProvider`:

```php
use App\Actions\Socialstream\CreateConnectedAccount;

Socialstream::createConnectedAccountsUsing(CreateConnectedAccount::class);
```

### Generate Provider Redirect Action

{% hint style="danger" %}
Impact: **High**
{% endhint %}

Socialstream 2.x includes a new action to generate the redirects URI's used to authenticate with providers.

You should then register this action with Socialstream by placing the following code into the `boot` method of your application's `SocialstreamServiceProvider`:

```php
use App\Actions\Socialstream\GenerateRedirectForProvider;

Socialstream::generatesProvidersRedirectsUsing(GenerateRedirectForProvider::class);
```

If you wish, you may override this action by writing your own. This may allow you to define `scopes` or additional parameters, such as a `response_type` for explicit grants. See below for an example.

> Note: the action **MUST** implement the `JoelButcher\Socialstream\Contracts\GeneratesProviderRedirect` contract.

```php
<?php

namespace App\Actions\Socialstream;

use JoelButcher\Socialstream\Contracts\GeneratesProviderRedirect;
use Laravel\Socialite\Facades\Socialite;

class GenerateRedirectForProvider implements GeneratesProviderRedirect
{
    /**
     * Generates the redirect for a given provider.
     *
     * @param  string  $provider
     *
     * @return \Symfony\Component\HttpFoundation\RedirectResponse
     */
    public function generate(string $provider)
    {
        return Socialite::driver($provider)
            ->scopes(['*'])
            ->with(['response_type' => 'token'])
            ->redirect();
    }
}
```

### Connected Account Credentials <a href="#user-content-connected-account-credentials" id="user-content-connected-account-credentials"></a>

{% hint style="info" %}
Impact: **Low**
{% endhint %}

For convenience, Socialstream now also provides a `Credentials` helper class which can be used for authenticating with additional provider API's (e.g. Facebook's Graph API).

You may retrieve an instance of this class from a connected account:

```php
$connectedAccount = \App\Models\ConnectedAccount::first();

$credentials = $connectedAccount->getCredentials();
```

### Inertia Stack <a href="#user-content-inertia-stack" id="user-content-inertia-stack"></a>

#### Authentication Views

To upgrade your application's authentication views to use the new Vue files from Jetstream 2.x, you should copy the [Jetstream auth files](https://github.com/laravel/jetstream/tree/2.x/stubs/inertia/resources/js/Pages/Auth), then the [Socialstream auth files](https://github.com/joelbutcher/socialstream/tree/2.x/stubs/inertia/resources/js/Pages/Auth) to the `resources/js/Pages/Auth` folder location.

You will also need to copy the [Providers.vue](https://github.com/joelbutcher/socialstream/blob/2.x/stubs/inertia/resources/js/Socialstream/Providers.vue) file to the `resources/js/Socialstream` directory.

However, if you wish to continue to render the Blade based authentication views, you should add the following code to the `boot` method of your application's `JetstreamServiceProvider` class:

```php
use Illuminate\Support\Facades\Route;
use Laravel\Fortify\Fortify;

Fortify::loginView(function () {
    return view('auth/login', [
        'canResetPassword' => Route::has('password.request'),
        'status' => session('status'),
    ]);
});

Fortify::requestPasswordResetLinkView(function () {
    return view('auth/forgot-password', [
        'status' => session('status'),
    ]);
});

Fortify::resetPasswordView(function (Request $request) {
    return view('auth/reset-password', [
        'email' => $request->input('email'),
        'token' => $request->route('token'),
    ]);
});

Fortify::registerView(function () {
    return view('auth/register');
});

Fortify::verifyEmailView(function () {
    return view('auth/verify-email', [
        'status' => session('status'),
    ]);
});

Fortify::twoFactorChallengeView(function () {
    return view('auth/two-factor-challenge');
});

Fortify::confirmPasswordView(function () {
    return view('auth/confirm-password');
});
```


# Contribution Guide

## Bug Reports

To encourage active collaboration, Socialstream strongly encourages pull requests, not just bug reports. Pull requests will only be reviewed when marked as "ready for review" (not in the "draft" state) and all tests for new features are passing. Lingering, non-active pull requests left in the "draft" state will be closed after a few days.

However, if you file a bug report, your issue should contain a title and a clear description of the issue. You should also include as much relevant information as possible and a code sample that demonstrates the issue. The goal of a bug report is to make it easy for yourself - and others - to replicate the bug and develop a fix.

Remember, bug reports are created in the hope that others with the same problem will be able to collaborate with you on solving it. Do not expect that the bug report will automatically see any activity or that others will jump to fix it. Creating a bug report serves to help yourself and others start on the path of fixing the problem. If you want to chip in, you can help out by fixing [any bugs listed in our issue trackers](https://github.com/joelbutcher/socialstream/issues). You must be authenticated with GitHub to view all of Socialstream's issues.

If you notice improper DocBlock, PHPStan, or IDE warnings while using Socialstream, do not create a GitHub issue. Instead, please submit a pull request to fix the problem.

The Socialstream source code is managed on GitHub.

## Which Branch?

**All** bug fixes should be sent to the latest version that supports bug fixes (currently `5.x`). Bug fixes should **never** be sent to the `main` branch unless they fix features that exist only in the upcoming release.

**Minor** features that are **fully backward compatible** with the current release may be sent to the latest stable branch (currently `5.x`).

**Major** new features or features with breaking changes should always be sent to the `main` branch, which contains the upcoming release.

## Security Vulnerabilities

If you discover a security vulnerability within Socialstream, please send an email to Joel Butcher at <joel@joelbutcher.com>. All security vulnerabilities will be promptly addressed.

## StyleCI

Don't worry if your code styling isn't perfect! StyleCI will automatically merge any style fixes into the Socialstream repository after pull requests are merged. This allows us to focus on the content of the contribution and not the code style.

## Code of Conduct

The Socialstream code of conduct is derived from the Ruby code of conduct. Any violations of the code of conduct may be reported to Joel Butcher (<joel@joelbutcher.com>):

* Participants will be tolerant of opposing views.
* Participants must ensure that their language and actions are free of personal attacks and disparaging personal remarks.
* When interpreting the words and actions of others, participants should always assume good intentions.
* Behavior that can be reasonably considered harassment will not be tolerated.

[<br>](https://srv.carbonads.net/ads/click/x/GTND42J7CASD523JCVB4YKQNF6AD423NCY7DPZ3JCYAIEKJLCWBDL2JKCVYDK27JF6ADT53LCT7IC5QYCTAIKZ3JCYAI52JWFTBDTK3K2JWNABY?segment=placement:laravelcom;)


# Installation

This page will walk you through how to get Socialstream up and running in a new Laravel application using Laravel Jetstream with Livewire 3. This example will use GitHub as the social provider.

{% hint style="warning" %}
Socialstream is designed to work in tandem with either of Laravel's starter kits (Breeze and Jetstream) and Filament Admin Panel, and as such, Socialstream should be installed into a **NEW** Laravel applications only. **It is not recommended to install Socialstream into an existing application.**
{% endhint %}

## Example Installation

To install Socialstream into your application you may use `composer`, you will then need to execute the `install` artisan command:

```
composer require joelbutcher/socialstream -W

php artisan socialstream:install
```

The install command will walk you through a bunch of options, such as the starter kit, for this example, choose `Laravel Jetstream`:

```
Socialstream supports Laravel Breeze, Laravel Jetstream, and Filament.

 ┌ Which development starter kit would you like to use? ────────┐
 │   ○ Laravel Breeze                                           │
 │ › ● Laravel Jetstream                                        │
 │   ○ Filament Admin Panel                                     │
 └──────────────────────────────────────────────────────────────┘
```

Next, we will need to choose the technology stack we wish to use, choose `Livewire`.

```
 ┌ Which stack would you like to use? ──────────────────────────┐
 │ › ● Livewire                                                 │
 │   ○ Vue with Inertia                                         │
 └──────────────────────────────────────────────────────────────┘
```

Next, select the optional features you wish to include with your application. In this example, we've decided we want to use Jetstreams `Dark mode` and `Team` features.

```
 ┌ Would you like any optional features? ───────────────────────┐
 │   ◻ API support                                              │
 │   ◼ Dark mode                                                │
 │   ◻ Email verification                                       │
 │ › ◼ Team support                                             │
 └──────────────────────────────────────────────────────────────┘
```

And finally, we have the option of selecting the testing framework we wish to use when building our application. Feel free to make your own decision at this step. In this example, I've chosen `Pest`, the best testing framework for PHP and Laravel.

```
 ┌ Which testing framework do you prefer? ──────────────────────┐
 │   ○ PHPUnit                                                  │
 │ › ● Pest                                                     │
 └──────────────────────────────────────────────────────────────┘
```

Once you've done this, Socialstream will install all the required dependencies for the options you've selected, including pulling in and installing Laravel Jetstream for you – no need to `composer require` another package manually yourself!

```
 Laravel Jetstream is not installed.


 Laravel Jetstream has been installed successfully!

 ⠂ Installing Socialstream...

 Making Socialstream compatible with teams

  Installed Socialstream for Laravel Jetstream (Livewire)
```

You can test the installation by running `php artisan serve` and visiting your application at [`http://127.0.0.1:8000`](http://127.0.0.1:8000):

<figure><img src="/files/jX25DrJPs1k333A6ZHIC" alt=""><figcaption><p><a href="http://127.0.0.1:8000/">http://127.0.0.1:8000/</a></p></figcaption></figure>

You'll notice that if you click on `Log in` or `Register` links at the top of the page that Socialstream isn't loaded, this is because we have a few things to configure before we can use Socialstream.

Firstly, we need to configure our OAuth provider. In this example, we will be using GitHub, head on over to GitHub and go to your profiles developer settings and create a new OAuth app:

<figure><img src="/files/0uqJ73XLuGu8VjVfFxKW" alt=""><figcaption><p>Register a new OAuth application</p></figcaption></figure>

When you have done this, you will be presented with your applications Client ID, make a note of this for later.

Next, click the `Generate a new client secret` button just under the Client ID. GitHub may prompt you to confirm this action via a 2FA prompt. Make a note of the Client Secret for later.

***

### Configuring the Github Provider

Now that we have our OAuth provider configured, we need to enable the provider in our application. Add the following code snippet to your applications `socialstream.php` config file:

```php
'providers' => [
    Providers::github(),
],
```

{% hint style="info" %}
You may change the text that appears on each providers button, by specifying a `label` in each provider: `Provider::github(label: 'My Provider')`.
{% endhint %}

Now, when you navigate to your applications `/register` route, you will now see the `Login via GitHub` option:

<figure><img src="/files/gQEhwa2TiWYhMx2N2wm7" alt="" width="375"><figcaption></figcaption></figure>

### Configure Client Credentials

The last thing to do, is configure the client credentials in your application. Add the following to your applications `services.php` config file:

```
    'github' => [
        'client_id' => '<your-client-id>',
        'client_secret' => '<your-client-secret>',
        'redirect' => '/oauth/github/callback',
    ],
```

{% hint style="info" %}
You may add a prefix to your applications Socialstream routes by specifying a `prefix` option in your `socialstream` config file:

```php
`prefix` => 'login',
```

This is especially helpful if you plan to use Laravel Passport, which also defines `/oauth` routes.
{% endhint %}

### Configure Socialstream Features

You may specify the socialstream features you wish for your app to support in the `features` array. A number are already added for you, with some commented out by default.

<pre class="language-php"><code class="lang-php"><strong>    'features' => [
</strong>        // Features::generateMissingEmails(),
        // Features::createAccountOnFirstLogin(),
        // Features::globalLogin(),
        // Features::authExistingUnlinkedUsers(),
        Features::rememberSession(),
        Features::providerAvatars(),
        Features::refreshOAuthTokens(),
    ],
</code></pre>

{% hint style="info" %}
The `providerAvatars` feature requires the `profilePhotos` Jetstream feature to be enabled for it to take affect.
{% endhint %}

## Installation Options

Socialstream supports a number of installation options depending on the starter kit (and stack) you choose to install. With each starter kit and stack, Socialstream will install all the required dependencies  for each one.

### Laravel Jetstream

Socialstream supports Laravel Jetstream with Vue (Inertia) or Livewire 3.0, with the following options:

* `--dark` – dark mode support
* `--api` – allows users to manage API tokens (distrubuted via Laravel Sanctum)
* `--verification` – user email verification
* `--teams` – Jetstreams team management features
* `--pest` – support for the best testing library for Laravel, Pest PHP
* `--ssr` – server side rendering (Vue with Inertia only)

### Laravel Breeze

Socialstream supports all of Laravel Breeze's stack options; including the new [Volt Class and Functional](https://livewire.laravel.com/docs/volt) API's.

The following options are available for Laravel Breeze:

* `--dark` – dark mode support
* `--pest` – support for the best testing library for Laravel, Pest PHP
* `--ssr` – server side rendering (Vue and React with Inertia only)
* `--typescript` – typescript support (Vue and React with Inertia only)

### Filament Admin Panels

Socialstream supports Filament Admin Panels, for admin login and registration (if enabled). It does this via a plugin extension for the `AdminPanelProvider`. It appends the `socialstream::components.socialstream` component to the bottom of both forms:

```php
$panel->renderHook('panels::auth.login.form.after', function () {
    return Socialstream::show() ?
        view(config('socialstream.component', 'socialstream::components.socialstream'), [
            'errors' => session('errors') ?? new ViewErrorBag(),
        ]) : '';
});

if ($panel->hasRegistration()) {
    $panel->renderHook('panels::auth.register.form.after', function () {
        return Socialstream::show() ?
            view(config('socialstream.component', 'socialstream::components.socialstream'), [
                'errors' => session('errors') ?? new ViewErrorBag(),
            ]) : '';
    });
}
```

{% hint style="info" %}
If you wish to change the layout of the views for filament, you may publish Socialstream components using the `vendor:publish` artisan command:

```sh
php artisan vendor:publish --tag=socialstream-views
```

{% endhint %}


# Configuration

After installing Socialstream, the primary configuration file will be located at `config/socialstream.php`. This configuration file allows you to configure the middleware Socialstream's routes sit behind, the prompt used to divide socialstream from the other authentication components on the `login` and `registration` panels, as well as the providers and features that are enabled.

## Middleware

By default, Socialstream uses the `web` middleware. For most applications, this should be the only middleware required for Socialstream's routes. However, you are free to change this to suit your applications needs.

## Prompt

The prompt is the text between the "Login" or "Registration" forms and Socialstreams OAuth buttons, this is set to `Or Login Via` by default. You are free to change this as you see fit.

## Providers

No providers are enabled by default (and thus the Socialstream section of the "Login" and "Registration" views is not rendered. However, you are free to enable as many providers as you wish.&#x20;

### Adding Providers

Socialstream natively only ships with support for the providers offered by [Laravel Socialite](https://laravel.com/docs/10.x/socialite). If you wish to add a provider, you may do so one of three ways:

#### Via the \`Providers\` static class

Socialstream ships with a `Providers` class, with static methods for each of Socialites supported providers. This class is imported in the default configuration file, and may be called like so:

```php
'providers' => [
    Providers::github(),
],
```

#### As a string

You may simply pass a string into the `providers` array within Socialstream's configuration file to add a provider.

{% hint style="warning" %}
Please note that the string value must also match the value of a service in your applications `services.php` configuration file as this is what is used to retrieve a providers credentials.
{% endhint %}

#### As an array

Additional providers may be added as an array:

```php
'providers' => [
    [
        'id' => 'github',
        'name' => 'GitHub',
    ],
]
```

The `id` property is the valid passed to Socialite when calling `Socialite::provider(...)` . This is then used by Socialite to resolve the OAuth credentials from your applications `config/services.php` file.

The `name` property is used in the "Connect Accounts" panel when rendering what providers are (or aren't) connected to your profile.

### Button Labels

As of v5, Socialstream now ships with the ability to define the button labels rendered in the "Login" and "Registration" buttions:

```php
// Via 'Providers' helper
Providers::github(label: 'Continue with GitHub'),

// Via array
[
    'id' => 'github',
    'name' => 'GitHub',
    'buttonLabel' => 'Continue with GitHub',
],
```

If a button label is not specified, Socialstream will fall back to the `name` property. If you have passed just a string, Socialstream will format the ID in a human readable way and render that as the button label instead.

## Features

You may specify which of Socialstream's features are enabled here, such as the profile avatar feature. Available feature options can be found in this sites navigation.


# Customization

Most applications will find the default installation for Socialstream sufficient for adding the benefit of Socialite OAuth integration into their next Laravel project. However, if you wish to customize certain elements, Socialstream makes this super easy for you by publishing a number of "actions" that you can change to suit your needs.

This section will detail all the ways you can customize Socialstream to get the most out of the package:

* [Socialite Redirect](/getting-started/customization/socialite-redirect)
* [Resolving Users](/getting-started/customization/resolving-users)
* [Handling the `InvalidStateException`](/getting-started/customization/handling-invalid-state)
* [Handling OAuth Callback Errors](/getting-started/customization/handling-oauth-errors)
* [Authenticating Users](/getting-started/customization/authenticating-users)


# Socialite Redirect

Socialstream generates the OAuth redirect for a provider using the following logic:

```php
Socialite::driver($provider)->redirect()
```

You may find you want to alter this logic; for example, you may wish to alter the scopes requested from the provider at runtime. To do so, simply update the `generate` method of your applications `app/Actions/Socialstream/GenerateRedirectForProvider.php` action file:

```php
public function generate(string $provider): RedirectResponse
{
    $scopes = ['*'];

    if ($provider = 'github' && config('services.github.manage_repos') {
        $scopes = array_merge($scopes, [
            'repos.manage',
        ]);
    }
    
    return Socialite::driver($provider)
        ->scopes($scopes)
        ->with(['response_type' => 'token'])
        ->redirect();
}
```


# Resolving Users

Socialstream resolves users from Socialite using the following logic:

```php
Socialite::driver($provider)->user();
```

However, you may decide you want to customise this functionality. For example, you may decide to use the `stateless` method to [disable state verification](https://laravel.com/docs/9.x/socialite#stateless-authentication). You may do this by updating the `resolve` method in `app/Actions/Socialstream/ResolveSocialiteUser.php`:

```php
/**
 * Resolve the user for a given provider.
 */
public function resolve(string $provider): User
{
    return match ($provider) {
        Providers::google() => Socialite::driver($provider)->stateless()->user(),
        default => Socialite::driver($provider)->user(),
    };
}
```


# Handling Invalid State

If you've ever used Socialite in the past, you may be familiar with the `InvalidStateException` you get if you try to refresh the callback route. When you first generate the redirect for a provider, Socialite will generate a random string 40 characters in length and store this in the session. When the user returns and `Socialite::driver(...)->user()` is called, this "pulls" the state stored in the session via `$request->session()->pull()`, and compares this value with a `state` parameter on the callback request.

Socialte will forget the state (remove it from the session) as soon as the value is retrieved from the session (see [here](https://github.com/laravel/framework/blob/a47df681bf4b72cb11e38f7ee7c285406ca934e0/src/Illuminate/Session/Store.php#L306-L309)). As such, subsequent attempts to the callback route will fail. To get around this, you can make both the redirect and callback requests "stateless". However, not all providers support this. You may, therefore, decide to alter this functionality on a per-provider basis. Socialite makes this easy for you, just update`app/Actions/Socialstream/HandleInvalidState.php` with logic specific to your use case.


# Handling OAuth Errors

When a user encounters an error returning from an OAuth flow, it will automatically detect the error and display this to the user:

<figure><img src="/files/l3nZM8IA7c9D9GGEi5oI" alt=""><figcaption></figcaption></figure>

This is done by grabbing the `error_description` from the request object and passing that value to a `socialstream` message bag. This can be accessed from your application:

```php
@error('socialstream')

$errors->get('socialstream');

session('errors')?->get('socialstream');
```

If you wish to customize how Socialstream handles callback errors, you may do so by creating an "action" that implements the `HandlesOauthCallbackErrors` contract and registering it with Socialstream in the `boot` method of a service provider:

```php
public function boot(): void
{
    Socialstream::handlesOAuthCallbackErrorsUsing(CustomOauthCallbackHandler::class);
}
```


# Authenticating Users

The main benefit of using Socialstream versus writing an OAuth integration for your Laravel application yourself, is that it handles all of the authentication logic for you. If you wish, you may override this logic, by registering your own "authenticator" with Socialstream. To do so, simply create a class that implements Socialstream's `AuthenticatesOauthCallback` contract, and register it with Socialstream via the `boot` method of a service provider:

```php
public function boot(): void
{
    Socialstream::authenticatesOauthCallbackUsing(CustomAuthenticateOauthCallback::class);
}
```


# Remember Session

This feature instructs Laravel's authentication layer to keep the user authenticated indefinitely, or until they manually logout. This feature is the equivalent of having the "remember me" checkbox on a login form checked.

In order for this feature to work, your `users` table must include the string `remember_token` column, which will be used to store the "remember me" token. The `users` table migration included with new Laravel applications already includes this column.

If you have this feature enabled, you may use the `viaRemember` method to determine if the currently authenticated user was authenticated using the "remember me" cookie:

```php
use Illuminate\Support\Facades\Auth;
 
if (Auth::viaRemember()) {
    // ...
}
```

To turn on this feature add the following to applications `socialstream.php` config file:

```php
Features::rememberSession()
```


# Refresh Expired Tokens

As of Socialstream v4.1.0, socialstream will now automatically check and refresh expired access tokens when they're retrieved from the database. To do this, socialstream uses the `client_id` and `client_secret` values stored in your applications services.php config file.

{% hint style="warning" %}
This may slow down your application depending on any delays in the request to the providers OAuth server.
{% endhint %}

This feature is enabled by default, to disable this feature, simply remove it from the `features` array inside your `socialstream.php` config file:

```php
Features::refreshOauthTokens()
```

You may wish to customise the logic behind refreshing an expired token, to do this, you can provide a closure to the `Socialstream::refreshesTokensForProviderUsing()` method from within the `boot` method of your applications `AppServiceProvider`. For example, for GitHub, this would look like the following:

```php
Socialstream::refreshesTokensForProviderUsing('github', function (ConnectedAccount $account) {
    $response = Http::asForm()->post(...);

    return new RefreshedCredentials(
        token: $response['access_token'],
        refreshToken: $response['refresh_token'],
        expiry: now()->addSeconds($response['expires_in']),
    );
});
```

Alternatively, you may provide the method with the FQN of a resolver class. This class must extend the base provider class from either Laravel Socialite, or the Socialite Providers package you are using. For example, if you were to use the `Reddit` provider from [socialiteproviders/reddit](https://github.com/SocialiteProviders/Reddit), you may define a class for refresh Reddit Oauth tokens and use that instead:

```php
<?php

namespace App\RefreshTokenProviders;

use GuzzleHttp\RequestOptions;
use JoelButcher\Socialstream\Concerns\RefreshesOauth2Tokens;
use JoelButcher\Socialstream\Contracts\Oauth2RefreshResolver;
use SocialiteProviders\Reddit\Provider as RedditProvider;

class RedditOauth2RefreshResolver extends RedditProvider implements Oauth2RefreshResolver
{
    use RefreshesOauth2Tokens;

    public function __construct()
    {
        parent::__construct(
            request: request(),
            clientId: config('services.reddit.client_id'),
            clientSecret: config('services.reddit.client_secret'),
            redirectUrl: '',
        );

        $this->guzzle = [
            RequestOptions::AUTH => [$this->clientId, $this->clientSecret],
        ];
    }
}
```

You would then add the following to the `boot` method of your applications `AppServiceProvider`:

```php
Socialstream::refreshesTokensForProviderUsing('reddit', RedditOauth2RefreshResolver::class);
```


# Provider Avatars

{% hint style="warning" %}
This feature requires you to have the [Profile Photos](https://jetstream.laravel.com/2.x/features/profile-management.html#profile-photos) feature enabled in Laravel Jetstream
{% endhint %}

The `Feature::providerAvatars()` feature instructs Socialstream to store the value of the `$avatar` property returned with the user data from Socialite after successfully authenticating with a provider.

Socialstream will download the image from the URL and use Jetstreams underlying Profile Photo's feature implementation so store the image in your specified disk. Please consult the [Jetstream documentation](https://jetstream.laravel.com/2.x/features/profile-management.html#managing-profile-photos) for more information on configuring this feature.

To turn on this feature add the following to applications `socialstream.php` config file:

```php
Features::providerAvatars()
```


# Global Login

You may have multiple pages where you allow users to authenticate with your application (such as a section at the bottom of your articles in a blog), then you may wish to avoid having to direct users to the `login`, or `registration` pages in order to authenticate them.

If this is the case, you can enable "Global Login" to allow users to authenticate from anywhere on your site. To do this, simply enable the following snippet to the `features` section of your socialstream config:

```php
Features::globalLogin(),
```


# Register from Login

This feature enables the capability to register a new user when a user attempts to authenticate via the '/login' route.

To turn on this feature add the following to applications `socialstream.php` config file:

```php
Features::createAccountOnFirstLogin()
```


# Missing Emails

Some providers (such as GitHub) don't always return an email address when authenticating with them. To attempt to solve this problem, Socialstream offers the ability to generate an email for any user this happens with. This email address is a unique combination of the `user_id` returned after authentication and the name of the provider used to authenticate with, coupled with your applications domain name:

```php
$email = "{$user->id}@{$provider}".config('app.domain');
```

{% hint style="info" %}
For example, for a GitHub user with the ID of 758273, the resulting email address would be `758273@github.myapp.com`
{% endhint %}

If you wish to customise how your application handles missing email, Socialstream publishes a `ResolveSocialiteUser.php` file containing this logic in your applications `app/Actions/Socialstream` directory:

```php
<?php

namespace App\Actions\Socialstream;

use JoelButcher\Socialstream\Contracts\ResolvesSocialiteUsers;
use JoelButcher\Socialstream\Socialstream;
use Laravel\Socialite\Contracts\User;
use Laravel\Socialite\Facades\Socialite;

class ResolveSocialiteUser implements ResolvesSocialiteUsers
{
    /**
     * Resolve the user for a given provider.
     */
    public function resolve(string $provider): User
    {
        $user = Socialite::driver($provider)->user();

        if (Socialstream::generatesMissingEmails()) {
            $user->email = $user->getEmail() ?? ("{$user->id}@{$provider}".config('app.domain'));
        }

        return $user;
    }
}
```

To turn on this feature add the following to applications `socialstream.php` config file:

```php
Features::generateMissingEmails(),
```


# Auth Existing Unlinked Users

This feature isn't new to Socialstream, but is a renamed version of the now deprecated ["Login on Registration"](/features/login-on-registration) feature.  <mark style="background-color:orange;">Please update your application to use this feature instead</mark>

Enable this feature if you wish to allow users to link a new provider to an existing user in your application without them being authenticated.

{% hint style="warning" %}
This feature can allow compromised social accounts unsolicited access to your users accounts.
{% endhint %}

To enable this feature, add the following to the `features` array of your `socialstream` config file:

```php
Features::authExistingUnlinkedUsers()
```


# Login on Registration (deprecated)

If a user has already registered with a particular email address, and the OAuth account they attempt to register with returns the same email, the provider will be linked to the existing user and they will be logged in.

{% hint style="warning" %}
This feature can allow compromised social accounts unsolicited access to your users accounts.
{% endhint %}

To turn on this feature add the following to applications `socialstream.php` config file:

```php
Features::loginOnRegistration()
```


# Standalone Installation

This guide will instruct you on how to install Socialstream as a standalone application. If you require additional functionality such as those provided by Laravel Jetstream, Laravel Breeze, or Filament, please follow the [standard installation guide](/getting-started/installation).

{% hint style="warning" %}
This guide assumes you are installing Socialstream into a fresh, blank blade-based Laravel application. If you are installing Socialstream into an existing Laravel app, or one built with Vue, React or another frontend technology, this guide will not work and will break your application.
{% endhint %}

***

## Installation

Please follow the [official documentation](https://laravel.com/docs/10.x) for getting started with a brand new Laravel application.

Once you have created your app, `cd` into your projects directory and install Socialstream via `composer`:

```sh
composer require joelbutcher/socialstream
```

You will then want to publish the configuration file and migrations required to get Socialstream working:

```
// Config
php artisan vendor:publish --tag=socialstream-config

// Migrations
php artisan vendor:publish --tag=socialstream-migrations
```

You will then want to run your migrations:

```
php artisan migrate
```

Next, you will want to follow the [official guide](https://tailwindcss.com/docs/guides/laravel) for installing Tailwind CSS into your Laravel application. Once you have done this, you will need to update the `content` option of your applications `tailwind.config.js` file to include Socialstream's `resources` directory and files:

```javascript
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    './vendor/joelbutcher/socialstream/resources/**/*.blade.php',
    ...
  ],
  ...
}
```

You may then add the Socialstream component into your application:

```php
<x-socialstream::socialstream />
```

Finally, you will want to install and build your frontend:

```sh
npm install && npm run build
```


# Filament with Jetstream

In some use cases, the need may arise for you to have multiple stacks installed within your application. For example, you may have a user-facing authenticated area to your app, as well as an admin panel built with Filament Admin Panel. This guide will instruct you on how to get your application set up for this scenario.

***

{% hint style="info" %}
This guide will assume you want to install the user-facing portion of your site via Laravel Jetstream and use Filament Admin Panel for staff. It also assumes you are using the same User model for both.

If you are using Laravel Breeze, please refer to [this guide](broken://pages/FmnvVo4MOtGf8NhYo7Hw).
{% endhint %}

## Installation

Firstly, you will want to install all the your dependencies via `composer`:

```sh
composer require laravel/jetstream filament/filament joelbutcher/socialstream
```

Once you have installed these dependencies, you may will want to run the install commands for both Jetstream and Filament **before** installing Socialstream:

```sh
php artisan jetstream:install <stack> <options>

php artisan filament:install --panels
```

{% hint style="warning" %}
Be sure to make a note of any optional features (such as teams support, dark mode, or email verification) as you will need this later on
{% endhint %}

Once you have done this, you will then need to install the Socialstream stack for Filament:

```sh
php artisan socialstream:install filament
```

This will ensure you have the base installation required for Socialstream to work with your application. It will also publish the required migrations, models and config files into your application for filament.

Next, you will need to install Socialstream for your desired Jetstream stack, ensuring to pass any options you may have opted-in for when installing Jetstream:

```sh
php artisan socialstream:install jetstream <stack> <options>
```

That's it! You can now enjoy using Socialstream for you application's users and for your apps admin panel.

***

## Notes

Because we installed Socialstream for Jetstream as the last step, the `User` model that was published by Filament will have been overwritten. To fix this, you may wish to re-add this into your User model:

```php
<?php

use Filament\Models\Contracts\FilamentUser;
use Filament\Panel;

class User extends Authenticatable implements FilamentUser
{
    public function canAccessPanel(Panel $panel): bool
    {
        return true;
    }
}
```


# Filament with Breeze

In some use cases, the need may arise for you to have multiple stacks installed within your application. For example, you may have a user-facing authenticated area to your app, as well as an admin panel built with Filament Admin Panel. This guide will instruct you on how to get your application set up for this scenario.

***

{% hint style="info" %}
This guide will assume you want to install the user-facing portion of your site via Laravel Breeze and use Filament Admin Panel for staff. It also assumes you are using the same User model for both.

If you are using Laravel Jetstream, please refer to [this guide](broken://pages/FmnvVo4MOtGf8NhYo7Hw).
{% endhint %}

## Installation

Firstly, you will want to install all the your dependencies via `composer`:

```sh
composer require laravel/breeze filament/filament joelbutcher/socialstream
```

Once you have installed these dependencies, you may will want to run the install commands for both Breeze and Filament **before** installing Socialstream:

```sh
php artisan breeze:install <stack> <options>

php artisan filament:install --panels
```

{% hint style="warning" %}
Be sure to make a note of any optional features (such as dark mode, or pest support) as you will need this later on
{% endhint %}

Once you have done this, you will then need to install the Socialstream stack for Filament:

```sh
php artisan socialstream:install filament
```

This will ensure you have the base installation required for Socialstream to work with your application. It will also publish the required migrations, models and config files into your application for filament.

Next, you will need to install Socialstream for your desired Breeze stack, ensuring to pass any options you may have opted-in for when installing Breeze:

```sh
php artisan socialstream:install breeze <stack> <options>
```

That's it! You can now enjoy using Socialstream for you application's users and for your apps admin panel.

***

## Notes

Because we installed Socialstream for Breeze as the last step, the `User` model that was published by Filament will have been overwritten. To fix this, you may wish to re-add this into your User model:

```php
<?php

use Filament\Models\Contracts\FilamentUser;
use Filament\Panel;

class User extends Authenticatable implements FilamentUser
{
    public function canAccessPanel(Panel $panel): bool
    {
        return true;
    }
}
```


# Laravel Passport

If you wish to use this package alongside Laravel Passport, you may encounter the following error message when attempting to authorise with Passports OAuth server:

```log
Driver [authorize] not supported
```

This is because Socialstream registers routes using the `oauth/{provider}` structure. This conflicts with Laravel Passports `oauth/authorize` route. To solve this, you may set a route `prefix` in your applications `socialstream.php` config file:

```
'prefix' => 'auth',
```

Alternatively, if you wish to keep the prefix Socialstream uses, you may edit Passport's route prefix in its config file. If you haven't already, publish Passport's config file:

```sh
php artisan vendor:publish --tag=passport-config
```

Add the following to `config/passport.php`:

```php
    /*
    |--------------------------------------------------------------------------
    | Path prefix
    |--------------------------------------------------------------------------
    |
    | Default is 'oauth'.
    |
    */

    'path' => 'passport-oauth',
```


# Socialite Providers

The aim of this guide is to walk you through setting up a fresh Laravel project with Jetstream, Socialstream and Socialite Providers.

{% hint style="info" %}
If you're unfamiliar with Laravel Socialite, Jetstream or Socialite Providers, we encourage you to read through their documentation before continuing with this guide.

* [Laravel Socialite](http://laravel.com/docs/10.x/socialite)
* [Laravel Jetstream](https://jetstream.laravel.com/introduction.html)
* [Socialite Providers](https://socialiteproviders.com/usage/)
  {% endhint %}

***

Before we begin, this guide assumes that you have already setup a fresh Laravel project with Socialstream. If this is not the case, check out the [Installation](/getting-started/installation) instructions for Socialstream.

## Installation

To install a socialite provider, you may do so via composer. For example, to add the Apple provider, you may execute the following command in your terminal:

```sh
composer require socialiteproviders/apple
```

## Setup

### Icons

First, we need to create an SVG icon or custom button component for the provider within your desired stack. You will then need to update the published components for your stack to cater for this provider:

**Livewire**

Icon location: `resources/views/components/socialstream-icons/`

* `resources/views/components/socialstream.blade.php`
* `resources/views/components/connected-account.blade.php`

**Inertia**

Icon location: `resources/js/Components/SocialstreamIcons/`

* `resources/js/Components/Socialstream.vue`
* `resources/js/Components/ConnectedAccount.vue`

## Config

### Socialstream Providers

Inside your applications `socialstream.php` config file, you will want to add the string representation of the SocialiteProvider you are adding support for. For example, if you are adding Sign in With Apple support, you would add the string `'apple'` to the `providers` array in `config/socialstream.php`

```php
'providers' => [
    \JoelButcher\Socialstream\Providers::github(),
    \JoelButcher\Socialstream\Providers::google(),
    [
        'id' => 'apple',
        'name' => 'Apple',
        'label' => 'Sign in with Apple',
    ],
],
```

### Service Provider

#### Laravel 11+

In `bootstrap/providers.php`.

```php
return [
    // a whole bunch of providers
    // remove 'Laravel\Socialite\SocialiteServiceProvider',
    \SocialiteProviders\Manager\ServiceProvider::class, // add
];
```

#### In Laravel 10 or Below

In `config\app.php`.

```php
'providers' => [
    // a whole bunch of providers
    // remove 'Laravel\Socialite\SocialiteServiceProvider',
    \SocialiteProviders\Manager\ServiceProvider::class, // add
];
```

### Add provider event listener

#### Laravel 11+

In Laravel 11, the default `EventServiceProvider` provider was removed. Instead, add the listener using the `listen` method on the `Event` facade, in your `AppServiceProvider` `boot` method.

* Note: You do not need to add anything for the built-in socialite providers unless you override them with your own providers.

```php
Event::listen(function (\SocialiteProviders\Manager\SocialiteWasCalled $event) {
    $event->extendSocialite('microsoft', \SocialiteProviders\Microsoft\Provider::class);
});
```

<details>

<summary>Laravel 10 or below</summary>

Configure the package's listener to listen for `SocialiteWasCalled` events.

Add the event to your `listen[]` array in `app/Providers/EventServiceProvider`. See the [Base Installation Guide](https://socialiteproviders.com/usage/) for detailed instructions.

```php
protected $listen = [
    \SocialiteProviders\Manager\SocialiteWasCalled::class => [
        // ... other providers
        \SocialiteProviders\Microsoft\MicrosoftExtendSocialite::class.'@handle',
    ],
];
```

<br>

</details>

### Database Changes – `token`

{% hint style="danger" %}
Some providers will not return a token in the callback response. As such, you will need to modify the `connected_accounts` table migration to make the `token` field nullable:

```php
$table->string('token', 1000)->nullable();
```

{% endhint %}


# Overriding Fortify's Authentication

{% hint style="success" %}
This guide looks to provide assistance that specifically tackles scenarios where you may be overriding Fortify's authentication pipeline. via `Fortify::authenticateUsing()`.
{% endhint %}

## Background

If you are using the Socialstream + Jetstream stack, you may want to opt-in to Fortify's Two Factor Authentication mechanics. When logging in via Socialstream, we have had to override two fundamental authentication classes with our own. The first is to create our own `eloquent`  user provider (found [here](https://github.com/joelbutcher/socialstream/blob/5309717b6d769ae9359844d518e835e1df894135/src/Auth/SocialstreamUserProvider.php) and registered [here](https://github.com/joelbutcher/socialstream/blob/d115bc82a4e15631faffcf512cbaf85e67ca8998/src/SocialstreamServiceProvider.php#L98-L101)). The second is to create our own version of Fortify's [login pipeline](https://github.com/laravel/fortify/blob/42695c45087e5abb3e173725b4f1ef4956a7b47d/src/Http/Controllers/AuthenticatedSessionController.php#L71) and use our own `RedirectIfTwoFactorAuthenticatable` class (which extends Fortify's one, but overrides the `validateCredentials` logic with our own).

If you're overriding the authentication pipeline to handle custom business logic (for example, [to check if a user has been blocked by an admin and redirect away if so](https://github.com/joelbutcher/socialstream/issues/370#issuecomment-2363262761)) you will need to make sure you include the same logic we use our `RedirectIfTwoFactorAuthenticatable` override, to make sure that login with socialstream providers still works.

```php
use App\Models\User;
use JoelButcher\Socialstream\Contracts\ResolvesSocialiteUsers;
use JoelButcher\Socialstream\Socialstream;
use Illuminate\Validation\ValidationException;

Fortify::authenticateUsing(function (Request $request) {
    if ($provider = $request->route('provider')) {
        $socialUser = app(ResolvesSocialiteUsers::class)
            ->resolve($provider);
    
        $connectedAccount = Socialstream::$connectedAccountModel::where('email', $socialUser->getEmail())->first();
    
        if (! $connectedAccount) {
            ValidationException::withMessages([
                Fortify::username() => [__('auth.failed')],
            ]);
        }
    
        return $connectedAccount->user;
    }
    // You're custom authentication logic here.
});
```

### Example

In this example, we're checking to see if a user has been blocked by and admin and returning a validation error if that is the case.

{% hint style="warning" %}
If you are following the example in Fortify's documentation and you are doing a hash check for the user entered password against the hash stored on the model, you will want to make sure you **don't** do this check for Socialstream routes.
{% endhint %}

First, check our route param to see if the user is coming from a Socialstream OAuth callback route:

```php
use App\Models\User;
use JoelButcher\Socialstream\Contracts\ResolvesSocialiteUsers;
use JoelButcher\Socialstream\Socialstream;
use Illuminate\Validation\ValidationException;

Fortify::authenticateUsing(function (Request $request) {
    $user = null;
    $provider = $request->route('provider');

    // 1a. Attempt the resolve the user via socialstream
    if ($provider) {
        $socialUser = app(ResolvesSocialiteUsers::class)
            ->resolve($provider);

        $connectedAccount = Socialstream::$connectedAccountModel::where('email', $socialUser->getEmail())->first();

        if (! $connectedAccount) {
            throw ValidationException::withMessages([
                Fortify::username() => [__('auth.failed')],
            ]);
        }

        $user = $connectedAccount->user;
    }

    // 1b. Attempt to resolve the user if email present in request (i.e. from login form).
    if (! $user && $request->has('email')) {
            $user = User::where('email', $request->email)->first();
    }

    // 2. Check if the resolved user is blocked and handle
    if ($user->blockedByAdmin()) {
        throw ValidationException::withMessages([
            Fortify::username() => [__('auth.blocked')],
        ]);
    }

    // 3. User is not blocked, log in if from Socialstream route
    if ($provider) {
        return $user;
    }

    // 4. User hasn't set a password, so must login using an OAuth provider
    if (is_null($user->password)) {
        throw ValidationException::withMessages([
            Fortify::username() => [__('auth.failed')],
        ]);
    }

    // 5. Verify the password if the user has logged in via a form
    return Hash::check($request->password, $user->password) ? $user : null;
});
```


