Skip to content

Commit 7d10b0b

Browse files
committed
Add OAuth blogpost
1 parent b13338d commit 7d10b0b

File tree

3 files changed

+130
-8
lines changed

3 files changed

+130
-8
lines changed

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"type": "project",
44
"description": "Documentation website for the Tempest framework",
55
"require": {
6-
"tempest/framework": "^2.1.0",
6+
"tempest/framework": "^2.2.0",
77
"league/commonmark": "^2.7.0",
88
"symfony/yaml": "^7.3.1",
99
"spatie/yaml-front-matter": "^2.1",

composer.lock

Lines changed: 7 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
---
2+
title: OAuth in Tempest 2.2
3+
description: Tempest 2.2 gets a new OAuth integration which makes authentication super simple
4+
author: brent
5+
tag: release
6+
---
7+
8+
Authentication is a challenging problem to solve. It's not just about logging a user in and session management, it's also about allowing them to manage their profile, email confirmation and password reset flows, custom authentication forms, 2FA, and what not. Ever since the start of Tempest, we've tried a number of approaches to have a built-in authentication layer that ships with the framework, and every time the solution felt suboptimal.
9+
10+
There is one big shortcut when it comes to authentication, though: outsource it to others. In other words: OAuth. Everything account-related can be managed by providers like Google, Meta, Apple, Discord, Slack, Microsoft, etc. All the while the implementation on our side stays incredibly simple. With the newest Tempest 2.2 release, we've added a firm foundation for OAuth support, backed by the incredible work done by the [PHP League](https://oauth2-client.thephpleague.com/). Here's how it works.
11+
12+
Tempest comes with support for many OAuth providers (thanks to the PHP League, again):
13+
14+
- [**GitHub**](https://github.com/tempestphp/tempest-framework/blob/main/packages/auth/src/OAuth/Config/GitHubOAuthConfig.php)
15+
- [**Google**](https://github.com/tempestphp/tempest-framework/blob/main/packages/auth/src/OAuth/Config/GoogleOAuthConfig.php)
16+
- [**Facebook**](https://github.com/tempestphp/tempest-framework/blob/main/packages/auth/src/OAuth/Config/FacebookOAuthConfig.php)
17+
- [**Discord**](https://github.com/tempestphp/tempest-framework/blob/main/packages/auth/src/OAuth/Config/DiscordOAuthConfig.php)
18+
- [**Instagram**](https://github.com/tempestphp/tempest-framework/blob/main/packages/auth/src/OAuth/Config/InstagramOAuthConfig.php)
19+
- [**LinkedIn**](https://github.com/tempestphp/tempest-framework/blob/main/packages/auth/src/OAuth/Config/LinkedInOAuthConfig.php)
20+
- [**Microsoft**](https://github.com/tempestphp/tempest-framework/blob/main/packages/auth/src/OAuth/Config/MicrosoftOAuthConfig.php)
21+
- [**Slack**](https://github.com/tempestphp/tempest-framework/blob/main/packages/auth/src/OAuth/Config/SlackOAuthConfig.php)
22+
- [**Apple**](https://github.com/tempestphp/tempest-framework/blob/main/packages/auth/src/OAuth/Config/AppleOAuthConfig.php)
23+
- Any other OAuth platform by using {b`Tempest\Auth\OAuth\Config\GenericOAuthConfig`}.
24+
25+
Whatever OAuth providers you want to support, it's as easy as making a config file for them like so:
26+
27+
```php app/Auth/github.config.php
28+
use Tempest\Auth\OAuth\Config\GitHubOAuthConfig;
29+
30+
return new GitHubOAuthConfig(
31+
tag: 'github',
32+
clientId: env('GITHUB_CLIENT_ID'),
33+
clientSecret: env('GITHUB_CLIENT_SECRET'),
34+
redirectTo: [GitHubAuthController::class, 'handleCallback'],
35+
scopes: ['user:email'],
36+
);
37+
```
38+
39+
```php app/Auth/discord.config.php
40+
use Tempest\Auth\OAuth\Config\DiscordOAuthConfig;
41+
42+
return new DiscordOAuthConfig(
43+
tag: 'discord',
44+
clientId: env('DISCORD_CLIENT_ID'),
45+
clientSecret: env('DISCORD_CLIENT_SECRET'),
46+
redirectTo: [DiscordAuthController::class, 'callback'],
47+
);
48+
```
49+
50+
Now we're ready to go. Generating a login link can be done by using the {b`Tempest\Auth\OAuth\OAuthClient`} interface:
51+
52+
```php
53+
namespace App\Auth;
54+
55+
use Tempest\Auth\OAuth\OAuthClient;
56+
use Tempest\Container\Tag;
57+
use Tempest\Router\Get;
58+
59+
final readonly class DiscordAuthController
60+
{
61+
public function __construct(
62+
#[Tag('discord')]
63+
private OAuthClient $oauth,
64+
) {}
65+
66+
#[Get('/auth/discord')]
67+
public function redirect(): Redirect
68+
{
69+
return $this->oauth->createRedirect();
70+
}
71+
72+
// …
73+
}
74+
```
75+
76+
Note how we're using [tagged singletons](/2.x/essentials/container#tagged-singletons) to inject our {b`Tempest\Auth\OAuth\OAuthClient`} instance. These tags come from the provider-specific configurations, and you can have as many different OAuth clients as you'd like. Finally, after a user was redirected and has authenticated with the OAuth provider, they will end up in the callback action, where we can authenticate the user on our side:
77+
78+
```php
79+
namespace App\Auth;
80+
81+
use Tempest\Auth\Authentication\Authenticatable;
82+
use Tempest\Auth\OAuth\OAuthClient;
83+
use Tempest\Auth\OAuth\OAuthUser;
84+
use Tempest\Container\Tag;
85+
use Tempest\Router\Get;
86+
87+
final readonly class DiscordAuthController
88+
{
89+
public function __construct(
90+
#[Tag('discord')]
91+
private OAuthClient $oauth,
92+
) {}
93+
94+
#[Get('/auth/discord')]
95+
public function redirect(): Redirect
96+
{
97+
return $this->oauth->createRedirect();
98+
}
99+
100+
#[Get('/auth/discord/callback')]
101+
public function callback(Request $request): Redirect
102+
{
103+
$this->oauth->authenticate(
104+
$request,
105+
function (OAuthUser $user): Authenticatable {
106+
return query(User::class)->updateOrCreate([
107+
'email' => $user->email,
108+
], [
109+
'discord_id' => $user->id,
110+
'username' => $user->nickname,
111+
]);
112+
}
113+
)
114+
115+
return new Redirect('/');
116+
}
117+
}
118+
```
119+
120+
As you can see, there's still a little bit of manual work involved within the OAuth callback action. That's because Tempest doesn't make any assumptions on how "users" are modeled within your project and thus you'll have to create or store those user credentials somewhere yourself. However, we also acknowledge that some kind of "default flow" would be useful for projects that just need a simple OAuth login with a range of providers. That's why we're now working on adding an OAuth installer: it will prompt you which providers to add in your project, prepare all config objects and controllers for you, and will assume you're using our built-in [user integration](/2.x/features/authentication).
121+
122+
All in all, I think this is a very solid base to build upon. You can read more about using Tempest's OAuth integration in the [docs](/2.x/features/oauth), and make sure to [join our Discord](/discord) if you want to stay in touch!

0 commit comments

Comments
 (0)