{"id":24962399,"url":"https://github.com/directorytree/bartender","last_synced_at":"2025-10-08T12:52:02.198Z","repository":{"id":231358584,"uuid":"780432067","full_name":"DirectoryTree/Bartender","owner":"DirectoryTree","description":"An opinionated way to authenticate users using Laravel Socialite.","archived":false,"fork":false,"pushed_at":"2025-10-02T03:51:38.000Z","size":87,"stargazers_count":279,"open_issues_count":1,"forks_count":13,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-10-02T05:38:16.968Z","etag":null,"topics":["laravel","oauth2","socialite"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/DirectoryTree.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"license.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-04-01T13:22:45.000Z","updated_at":"2025-10-02T03:51:42.000Z","dependencies_parsed_at":"2024-04-25T21:23:34.702Z","dependency_job_id":"28a71c5c-b02a-4b25-999f-0ffd6c1ae55e","html_url":"https://github.com/DirectoryTree/Bartender","commit_stats":null,"previous_names":["directorytree/bartender"],"tags_count":12,"template":false,"template_full_name":null,"purl":"pkg:github/DirectoryTree/Bartender","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DirectoryTree%2FBartender","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DirectoryTree%2FBartender/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DirectoryTree%2FBartender/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DirectoryTree%2FBartender/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/DirectoryTree","download_url":"https://codeload.github.com/DirectoryTree/Bartender/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DirectoryTree%2FBartender/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278948024,"owners_count":26073747,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-08T02:00:06.501Z","response_time":56,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["laravel","oauth2","socialite"],"created_at":"2025-02-03T09:00:05.210Z","updated_at":"2025-10-08T12:52:02.192Z","avatar_url":"https://github.com/DirectoryTree.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n\u003cimg src=\"https://github.com/DirectoryTree/Bartender/blob/master/art/logo.svg\" width=\"250\"\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\nAn opinionated way to authenticate users using Laravel Socialite.\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n\u003ca href=\"https://github.com/directorytree/bartender/actions\" target=\"_blank\"\u003e\u003cimg src=\"https://img.shields.io/github/actions/workflow/status/directorytree/bartender/run-tests.yml?branch=master\u0026style=flat-square\"/\u003e\u003c/a\u003e\n\u003ca href=\"https://packagist.org/packages/directorytree/bartender\" target=\"_blank\"\u003e\u003cimg src=\"https://img.shields.io/packagist/v/directorytree/bartender.svg?style=flat-square\"/\u003e\u003c/a\u003e\n\u003ca href=\"https://packagist.org/packages/directorytree/bartender\" target=\"_blank\"\u003e\u003cimg src=\"https://img.shields.io/packagist/dt/directorytree/bartender.svg?style=flat-square\"/\u003e\u003c/a\u003e\n\u003ca href=\"https://packagist.org/packages/directorytree/bartender\" target=\"_blank\"\u003e\u003cimg src=\"https://img.shields.io/packagist/l/directorytree/bartender.svg?style=flat-square\"/\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n---\n\nBartender serves you a controller, routes, and a default implementation for easily handling authentication with Laravel Socialite providers.\n\nAlmost everything in Bartender can be customized.\n\n## Index\n\n- [Requirements](#requirements)\n- [Installation](#installation)\n- [Setup](#setup)\n- [Usage](#usage)\n  - [Soft Deletes](#soft-deletes)\n  - [Email Verification](#email-verification)\n  - [Access/Refresh Tokens](#accessrefresh-tokens)\n- [Extending \u0026 Customizing](#extending--customizing)\n\n## Requirements\n\n- PHP \u003e= 8.0\n- Laravel \u003e= 9.0\n- Laravel Socialite \u003e= 5.0\n\n## Installation\n\nYou can install the package via composer:\n\n```bash\ncomposer require directorytree/bartender\n```\n\nThen, publish the migrations. They will create the required columns on the `users` table:\n\n- `provider_id`\n- `provider_name`\n- `provider_access_token`\n- `provider_refresh_token`\n\n\u003e If your application does not need to store/access provider tokens, you may delete the `2024_10_27_131354_add_provider_token_columns_to_users_table.php` migration.\n\n```bash\nphp artisan vendor:publish --provider=\"DirectoryTree\\Bartender\\BartenderServiceProvider\"\n```\n\nFinally, run the migrations:\n\n```bash\nphp artisan migrate\n```\n\n## Setup\n\nRegister the authentication routes using `Bartender::routes()`.\n\nThis will register the `/auth/{driver}/redirect` and `/auth/{driver}/callback` routes.\n\n```php\n// routes/web.php\n\nuse DirectoryTree\\Bartender\\Facades\\Bartender;\n\nBartender::routes();\n```\n\nSet up any [Socialite Providers](https://socialiteproviders.com) you need, and update your `services.php` configuration file with the `redirect` URL for each provider:\n\n\u003e [!important]\n\u003e Remember to fully complete the installation steps for each Socialite Provider you wish to use.\n\u003e \n\u003e If you receive a `Driver [X] not supported` exception, you have not completed the installation steps for the provider.\n\n```php\n// config/services.php\n\nreturn [\n    // ...\n\n    'google' =\u003e [\n        // ...\n        'redirect' =\u003e '/auth/google/callback',\n    ],\n    \n    'microsoft' =\u003e [\n        // ...\n        'redirect' =\u003e '/auth/microsoft/callback',\n    ],\n];\n```\n\nFinally, register the Socialite Provider in your `AppServiceProvider` using `Bartender::serve()`:\n\n```php\n// app/Providers/AppServiceProvider.php\n\nuse DirectoryTree\\Bartender\\Facades\\Bartender;\n\nclass AppServiceProvider extends ServiceProvider\n{\n    // ...\n\n    public function boot(): void\n    {\n        Bartender::serve('google');\n        Bartender::serve('microsoft');\n    }\n}\n```\n\nIf your application uses a `User` model outside the default `App\\Models` namespace, you can set it using the `Bartender` facade.\n\n\u003e If your application uses the default Laravel `User` model in the `App\\Models` namespace, skip this step.\n\n```php\n// app/Providers/AuthServiceProvider.php\n\nuse App\\User;\nuse DirectoryTree\\Bartender\\Facades\\Bartender;\n\nclass AuthServiceProvider extends ServiceProvider\n{\n    // ...\n\n    public function boot(): void\n    {\n        Bartender::setUserModel(User::class);\n    }\n}\n```\n\n## Usage\n\nDirect your user to the `/auth/{driver}/redirect` route to authenticate with the given driver:\n\n```blade\n\u003ca href=\"{{ route('auth.driver.redirect', 'google') }}\"\u003e\n    Login with Google\n\u003c/a\u003e\n\n\u003ca href=\"{{ route('auth.driver.redirect', 'microsoft') }}\"\u003e\n    Login with Microsoft\n\u003c/a\u003e\n```\n\nOnce the user successfully authenticates, they will be redirected to the `/auth/{driver}/callback` \nroute, which will automatically create or update their application user account.\n\n\u003e [!important]\n\u003e If you receive a `Routing requirement for \"driver\" cannot be empty` exception upon clicking\n\u003e one of the login links, you have forgotten to register your the Socialite provider with\n\u003e Bartender using `Bartender::serve()` in your `AppServiceProvider`.\n\n### Soft Deletes\n\nWith the default `UserProviderRepository`, users will be restored if they are soft-deleted and the login with their provider.\n\nTo change this behaviour, [swap out the repository](#user-creation--updating).\n\n### Email Verification\n\nWith the default `UserProviderRepository`, users with emails will be automatically verified (via the `email_verified_at` column) if it is not already set.\n\nTo change this behaviour, [swap out the repository](#user-creation--updating).\n\n### Access/Refresh Tokens\n\nTo enable storing the authentication provider access and refresh tokens \non your user so that you can access them later, you may apply the\n`StoresProviderTokens` interface on your model:\n\n```php\n// app/Models/User.php\n\nnamespace App\\Models;\n\nuse DirectoryTree\\Bartender\\StoresProviderTokens;\n\nclass User extends Authenticatable implements StoresProviderTokens\n{\n    // ...    \n}\n```\n\nYou may also want to add these columns to your model's `$hidden` attributes, as well as `encrypted` casts for additional security:\n\n```php\n// app/Models/User.php\n\nclass User extends Authenticatable implements StoresProviderTokens\n{\n    /**\n     * The attributes that should be hidden for serialization.\n     */\n    protected $hidden = [\n        'provider_access_token',\n        'provider_refresh_token'\n    ];\n\n    /**\n     * Get the attributes that should be cast.\n     */\n    protected function casts(): array\n    {\n        return [\n            'provider_access_token' =\u003e 'encrypted',\n            'provider_refresh_token' =\u003e 'encrypted',\n        ];\n    }\n}\n```\n\nOtherwise, if you do not need to store these tokens, you are free to delete the \npublished `2024_10_27_131354_add_provider_token_columns_to_users_table.php` \nmigration file and omit applying the `StoresProviderTokens` interface.\nBartender will skip storing these tokens as it does not\nrequire them to successfully authenticate users.\n\n## Extending \u0026 Customizing\n\nAlmost everything can be swapped out in Bartender.\n\nIf you would like to handle everything yourself for OAuth redirects and callbacks, you may create your own `ProviderHandler`:\n\n```php\n// app/Socialite/UserProviderHandler.php\n\nnamespace App\\Socialite;\n\nuse Illuminate\\Http\\Request;\nuse Laravel\\Socialite\\Contracts\\Provider;\nuse DirectoryTree\\Bartender\\ProviderHandler;\n\nclass UserProviderHandler implements ProviderHandler\n{\n    /**\n     * Constructor.\n     */\n    public function __construct(\n        protected Request $request\n    ) {\n    }\n\n    /**\n     * Handle redirecting the user to the OAuth provider.\n     */\n    public function redirect(Provider $provider, string $driver): RedirectResponse\n    {\n        // Perform additional logic here...\n    \n        return $provider-\u003eredirect();\n    }\n\n    /**\n     * Handle an OAuth response from the provider.\n     */\n    public function callback(Provider $provider, string $driver): RedirectResponse\n    {\n        // Authenticate the user your own way...\n    \n        return redirect()-\u003eroute('dashboard');\n    }\n}\n```\n\nThen, provide it into the second argument in the `Bartender::serve` method:\n\n```php\n// app/Providers/AuthServiceProvider.php\n\nnamespace App\\Providers;\n\nuse App\\Socialite\\UserProviderHandler;\nuse DirectoryTree\\Bartender\\Facades\\Bartender;\n\nclass AuthServiceProvider extends ServiceProvider\n{\n    // ...\n\n    public function boot(): void\n    {\n        Bartender::serve('google', UserProviderHandler::class);\n        Bartender::serve('microsoft', UserProviderHandler::class);\n    }\n}\n```\n\nYou may also extend the built-in `UserProviderHandler` implementation if you prefer.\n\nFor example, if you need to adjust the scopes for a single provider:\n\n```php\n// app/Socialite/MicrosoftUserHandler.php\n\nnamespace App\\Socialite;\n\nuse Illuminate\\Http\\RedirectResponse;\nuse Laravel\\Socialite\\Contracts\\Provider;\nuse DirectoryTree\\Bartender\\UserProviderHandler;\n\nclass MicrosoftUserHandler extends UserProviderHandler\n{\n    /**\n     * Handle redirecting the user to Microsoft.\n     */\n    public function redirect(Provider $provider, string $driver): RedirectResponse\n    {\n        $provider-\u003escopes([\n            'Mail.ReadWrite',\n            // ...\n        ]);\n    \n        return parent::redirect($provider, $driver);\n    }\n}\n```\n\nThen register it as the handler:\n\n```php\nBartender::serve('microsoft', MicrosoftUserHandler::class);\n```\n\n### User Creation \u0026 Updating\n\nIf you would like to customize the creation of the user in the default\nhandler, you may create your own `ProviderRepository` implementation:\n\n```php\n// app/Socialite/UserProviderRepository.php\n\nnamespace App\\Socialite;\n\nuse App\\Models\\User;\nuse Illuminate\\Contracts\\Auth\\Authenticatable;\nuse DirectoryTree\\Bartender\\ProviderRepository;\nuse Laravel\\Socialite\\Contracts\\User as SocialiteUser;\n\nclass UserProviderRepository implements ProviderRepository\n{\n    /**\n     * Determine if the user already exists under a different provider.\n     */\n    public function exists(string $driver, SocialiteUser $user): bool\n    {\n        return User::withTrashed()-\u003ewhere('...')-\u003eexists();\n    }\n\n    /**\n     * Update or create the socialite user.\n     */\n    public function updateOrCreate(string $driver, SocialiteUser $user): Authenticatable\n    {\n        $user = User::withTrashed()-\u003efirstOrNew([\n            // ...\n        ]);\n        \n        return $user;\n    }\n}\n```\n\nThen, bind your implementation in the service container in your `AppServiceProvider`:\n\n```php\n// app/Providers/AppServiceProvider.php\n\nnamespace App\\Providers;\n\nuse App\\Socialite\\UserProviderRepository;\nuse DirectoryTree\\Bartender\\ProviderRepository;\n\nclass AppServiceProvider extends ServiceProvider\n{\n    // ...\n\n    public function register(): void\n    {\n        $this-\u003eapp-\u003ebind(ProviderRepository::class, UserProviderRepository::class);\n    }\n}\n```\n\n### User Redirects \u0026 Flash Messaging\n\nIf you would like to customize the behavior of the redirects of the default \nredirector and flash messages depending on the outcome of a OAuth callback, \nyou can create your own `ProviderRedirector` implementation:\n\n\u003e It's recommended to regenerate the session after authentication to prevent users\n\u003e from exploiting a [session fixation attack](https://laravel.com/docs/11.x/session#regenerating-the-session-id).\n\n```php\n// app/Socialite/UserProviderRedirector.php\n\nnamespace App\\Socialite;\n\nuse Illuminate\\Support\\Facades\\Auth;\nuse Illuminate\\Support\\Facades\\Session;\n\nclass UserProviderRedirector implements ProviderRedirector\n{\n    /**\n     * Redirect when unable to authenticate the user.\n     */\n    public function unableToAuthenticateUser(Exception $e, string $driver): RedirectResponse\n    {\n        report($e);\n\n        return redirect()-\u003eroute('login')-\u003ewith('error', 'Unable to authenticate user.');\n    }\n\n    /**\n     * Redirect when the user already exists.\n     */\n    public function userAlreadyExists(SocialiteUser $user, string $driver): RedirectResponse\n    {\n        return redirect()-\u003eroute('login')-\u003ewith('error', 'User already exists.');\n    }\n\n    /**\n     * Redirect when unable to create the user.\n     */\n    public function unableToCreateUser(Exception $e, SocialiteUser $user, string $driver): RedirectResponse\n    {\n        report($e);\n\n        return redirect()-\u003eroute('login')-\u003ewith('error', 'Unable to create user.');\n    }\n\n    /**\n     * Handle when the user has been successfully authenticated.\n     */\n    public function userAuthenticated(Authenticatable $user, SocialiteUser $socialite, string $driver): RedirectResponse\n    {\n        Auth::login($user);\n        \n        Session::regenerate();\n    \n        return redirect()-\u003eroute('dashboard');\n    }\n}\n```\n\nThen, bind your implementation in the service container in your `AppServiceProvider`:\n\n```php\n// app/Providers/AppServiceProvider.php\n\nnamespace App\\Providers;\n\nuse App\\Socialite\\UserProviderRedirector;\n\nclass AppServiceProvider extends ServiceProvider\n{\n    // ...\n\n    public function register(): void\n    {\n        $this-\u003eapp-\u003ebind(ProviderRedirector::class, UserProviderRedirector::class);\n    }\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdirectorytree%2Fbartender","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdirectorytree%2Fbartender","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdirectorytree%2Fbartender/lists"}