Skip to content

Commit f94cfcd

Browse files
committed
wip
1 parent 9ef1359 commit f94cfcd

File tree

4 files changed

+84
-7
lines changed

4 files changed

+84
-7
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Tempest\Auth\Exceptions;
6+
7+
use Exception;
8+
9+
final class OAuthStateWasInvalid extends Exception implements AuthenticationException
10+
{
11+
}

packages/auth/src/OAuth/GenericOAuthClient.php

Lines changed: 48 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,29 +4,57 @@
44

55
namespace Tempest\Auth\OAuth;
66

7+
use BackedEnum;
8+
use Closure;
79
use League\OAuth2\Client\Provider\AbstractProvider;
810
use League\OAuth2\Client\Provider\Exception\IdentityProviderException;
911
use League\OAuth2\Client\Token\AccessToken;
12+
use Tempest\Auth\Authentication\Authenticatable;
13+
use Tempest\Auth\Authentication\Authenticator;
14+
use Tempest\Auth\Exceptions\OAuthStateWasInvalid;
1015
use Tempest\Auth\Exceptions\OAuthTokenCouldNotBeRetrieved;
1116
use Tempest\Auth\Exceptions\OAuthUserCouldNotBeRetrieved;
17+
use Tempest\Http\Request;
18+
use Tempest\Http\Session\Session;
1219
use Tempest\Mapper\ObjectFactory;
1320
use Tempest\Router\UriGenerator;
21+
use UnitEnum;
1422

15-
final readonly class GenericOAuthClient implements OAuthClient
23+
final class GenericOAuthClient implements OAuthClient
1624
{
1725
private AbstractProvider $provider;
1826

1927
public function __construct(
20-
private(set) OAuthConfig $config,
21-
private UriGenerator $uri,
22-
private ObjectFactory $factory,
28+
private(set) readonly OAuthConfig $config,
29+
private readonly UriGenerator $uri,
30+
private readonly ObjectFactory $factory,
31+
private readonly Session $session,
32+
private readonly Authenticator $authenticator,
2333
?AbstractProvider $provider = null,
24-
) {
34+
)
35+
{
2536
$this->provider = $provider ?? $this->config->createProvider();
2637
}
2738

39+
public string $sessionKey {
40+
get {
41+
$tag = $this->config->tag;
42+
43+
$key = match (true) {
44+
is_string($tag) => $tag,
45+
$tag instanceof BackedEnum => $tag->value,
46+
$tag instanceof UnitEnum => $tag->name,
47+
default => 'default',
48+
};
49+
50+
return "oauth:{$key}";
51+
}
52+
}
53+
2854
public function getAuthorizationUrl(array $scopes = [], array $options = []): string
2955
{
56+
$this->session->set($this->sessionKey, $this->provider->getState());
57+
3058
return $this->provider->getAuthorizationUrl([
3159
'scope' => $scopes ?? $this->config->scopes,
3260
'redirect_uri' => $this->uri->createUri($this->config->redirectTo),
@@ -69,4 +97,19 @@ public function fetchUser(string $code): OAuthUser
6997
token: $this->getAccessToken($code),
7098
);
7199
}
100+
101+
public function authenticate(Request $request, Closure $authenticate): Authenticatable
102+
{
103+
if ($this->session->get($this->sessionKey) !== $request->get('state')) {
104+
throw new OAuthStateWasInvalid();
105+
}
106+
107+
$user = $this->fetchUser($request->get('code'));
108+
109+
$authenticable = $authenticate($user);
110+
111+
$this->authenticator->authenticate($authenticable);
112+
113+
return $authenticable;
114+
}
72115
}

packages/auth/src/OAuth/OAuthClient.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@
44

55
namespace Tempest\Auth\OAuth;
66

7+
use Closure;
78
use League\OAuth2\Client\Token\AccessToken;
9+
use Tempest\Auth\Authentication\Authenticatable;
10+
use Tempest\Http\Request;
811

912
interface OAuthClient
1013
{
@@ -32,4 +35,10 @@ public function getUser(AccessToken $token): OAuthUser;
3235
* Completes OAuth flow with code and get user information.
3336
*/
3437
public function fetchUser(string $code): OAuthUser;
38+
39+
/**
40+
* Authenticates a user based on the given oauth callback request
41+
* @param Closure(\Tempest\Auth\OAuth\OAuthUser $user): Authenticatable $authenticate
42+
*/
43+
public function authenticate(Request $request, Closure $authenticate): Authenticatable;
3544
}

packages/auth/src/OAuth/Testing/TestingOAuthClient.php

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,15 @@
44

55
namespace Tempest\Auth\OAuth\Testing;
66

7+
use Closure;
78
use League\OAuth2\Client\Token\AccessToken;
89
use PHPUnit\Framework\Assert;
10+
use Tempest\Auth\Authentication\Authenticatable;
11+
use Tempest\Auth\Authentication\Authenticator;
912
use Tempest\Auth\OAuth\OAuthClient;
1013
use Tempest\Auth\OAuth\OAuthConfig;
1114
use Tempest\Auth\OAuth\OAuthUser;
15+
use Tempest\Http\Request;
1216
use Tempest\Router\UriGenerator;
1317
use Tempest\Support\Arr;
1418
use Tempest\Support\Random;
@@ -46,8 +50,9 @@ final class TestingOAuthClient implements OAuthClient
4650

4751
public function __construct(
4852
private(set) OAuthUser $user,
49-
private(set) OAuthConfig $config,
50-
private UriGenerator $uri,
53+
private(set) readonly OAuthConfig $config,
54+
private readonly Authenticator $authenticator,
55+
private readonly UriGenerator $uri,
5156
) {}
5257

5358
public function getAuthorizationUrl(array $scopes = [], array $options = []): string
@@ -115,6 +120,15 @@ public function fetchUser(string $code): OAuthUser
115120
return $user;
116121
}
117122

123+
public function authenticate(Request $request, Closure $authenticate): Authenticatable
124+
{
125+
$authenticatable = $authenticate($this->user);
126+
127+
$this->authenticator->authenticate($authenticatable);
128+
129+
return $authenticatable;
130+
}
131+
118132
/**
119133
* Sets the OAuth client ID.
120134
*/

0 commit comments

Comments
 (0)