OAuth2 — an authorization framework, not an authentication protocol
Concept
OAuth2 — an authorization framework (not authentication!) that allows third-party applications to access a user's resources on another service, without exposing the user's credentials.
The problem OAuth2 solves: You want your app to post tweets on behalf of users. Without OAuth, you'd ask for their Twitter password — terrible security. With OAuth2, Twitter shows the user a consent screen, and if approved, gives YOUR APP a token scoped to specific permissions ("post tweets"). Your app never sees their Twitter password.
Key roles:
- Resource Owner: The user who owns the data.
- Client: Your application requesting access.
- Authorization Server: Issues tokens (e.g., Twitter's auth server).
- Resource Server: The API with the protected resources (Twitter's API).
OAuth2 Grant Types:
- Authorization Code (+ PKCE): For web apps and mobile. Most secure. User redirected to auth server, gets a code, code exchanged for token.
- Client Credentials: Machine-to-machine. No user involved. Your server authenticates to another server.
- Device Code: For TVs/CLIs with no browser.
- Implicit (deprecated): Was for SPAs. Replaced by Authorization Code + PKCE.
OAuth2 vs OpenID Connect (OIDC): OAuth2 is for AUTHORIZATION (access to resources). OIDC adds an identity layer on top of OAuth2 (for AUTHENTICATION — "who is this user?"). "Login with Google" = OIDC.
In Laravel: laravel/socialite for OAuth2 login (Google, GitHub, etc.). laravel/passport for building your own OAuth2 server.
Code Example
<?php
// OAUTH2 CLIENT — Login with GitHub (using Laravel Socialite)
// composer require laravel/socialite
// config/services.php
// 'github' => [
// 'client_id' => env('GITHUB_CLIENT_ID'),
// 'client_secret' => env('GITHUB_CLIENT_SECRET'),
// 'redirect' => env('GITHUB_REDIRECT_URI'),
// ],
// routes/web.php
Route::get('/auth/github', [SocialAuthController::class, 'redirect']);
Route::get('/auth/github/callback', [SocialAuthController::class, 'callback']);
class SocialAuthController extends Controller
{
// Step 1: Redirect user to GitHub
public function redirect(): RedirectResponse
{
return Socialite::driver('github')
->scopes(['read:user', 'user:email']) // request only needed permissions
->redirect();
// User sees: "The Framework Architect wants to access your email address. Allow?"
}
// Step 2: GitHub redirects back with ?code=abc123
// Socialite exchanges code for access token, fetches user info
public function callback(): RedirectResponse
{
$githubUser = Socialite::driver('github')->user();
$user = User::updateOrCreate(
['github_id' => $githubUser->getId()],
[
'name' => $githubUser->getName(),
'email' => $githubUser->getEmail(),
'avatar_url' => $githubUser->getAvatar(),
]
);
Auth::login($user, remember: true);
return redirect()->intended('/dashboard');
}
}
// OAUTH2 SERVER — building your own (Laravel Passport)
// composer require laravel/passport
// php artisan passport:install
// Issuing tokens for your own API
$token = $user->createToken(
name: 'mobile-app',
scopes: ['read-orders', 'create-orders'] // scoped access
)->accessToken;
// Protecting routes
Route::middleware(['auth:api', 'scope:read-orders'])->group(function () {
Route::get('/orders', [OrderController::class, 'index']);
});
// CLIENT CREDENTIALS — machine-to-machine
// Other services authenticate with client_id + client_secret
// No user involved