Completed
Push — develop ( 5503b1...6a0d81 )
by Abdelrahman
19:31 queued 18:12
created

PersonalAccessTokenFactory::make()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 19
rs 9.6333
c 0
b 0
f 0
cc 1
nc 1
nop 3
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Rinvex\Oauth\Factories;
6
7
use RuntimeException;
8
use Nyholm\Psr7\Response;
9
use Nyholm\Psr7\ServerRequest;
10
use Rinvex\Oauth\Models\Client;
11
use Lcobucci\JWT\Parser as JwtParser;
12
use Illuminate\Database\Eloquent\Model;
13
use Rinvex\Oauth\PersonalAccessTokenResult;
14
use Psr\Http\Message\ServerRequestInterface;
15
use League\OAuth2\Server\AuthorizationServer;
16
17
class PersonalAccessTokenFactory
18
{
19
    /**
20
     * The authorization server instance.
21
     *
22
     * @var \League\OAuth2\Server\AuthorizationServer
23
     */
24
    protected $server;
25
26
    /**
27
     * The JWT token parser instance.
28
     *
29
     * @var \Lcobucci\JWT\Parser
30
     */
31
    protected $jwt;
32
33
    /**
34
     * Create a new personal access token factory instance.
35
     *
36
     * @param \League\OAuth2\Server\AuthorizationServer $server
37
     * @param \Lcobucci\JWT\Parser                      $jwt
38
     *
39
     * @return void
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
40
     */
41
    public function __construct(AuthorizationServer $server, JwtParser $jwt)
42
    {
43
        $this->jwt = $jwt;
44
        $this->server = $server;
45
    }
46
47
    /**
48
     * Create a new personal access token.
49
     *
50
     * @param \Illuminate\Database\Eloquent\Model $user
51
     * @param string                              $name
52
     * @param array                               $scopes
53
     *
54
     * @return \Rinvex\Oauth\PersonalAccessTokenResult
55
     */
56
    public function make(Model $user, $name, array $scopes = [])
57
    {
58
        $response = $this->dispatchRequestToAuthorizationServer(
59
            $this->createRequest($this->personalAccessClient(), $user, $scopes)
60
        );
61
62
        $accessToken = tap($this->findAccessToken($response), function ($accessToken) use ($user, $name) {
63
            $accessToken->forceFill([
64
                'user_id' => $user->getAuthIdentifier(),
65
                'user_type' => $user->getMorphClass(),
66
                'name' => $name,
67
            ])->save();
68
        });
69
70
        return new PersonalAccessTokenResult(
71
            $response['access_token'],
72
            $accessToken
73
        );
74
    }
75
76
    /**
77
     * Get the personal access token client for the application.
78
     *
79
     * @throws \RuntimeException
80
     *
81
     * @return \Rinvex\Oauth\Models\Client
82
     */
83
    public function personalAccessClient()
84
    {
85
        if ($personalAccessClientId = config('rinvex.oauth.personal_access_client.id')) {
86
            return app('rinvex.oauth.client')->resolveRouteBinding($personalAccessClientId);
87
        }
88
89
        $client = app('rinvex.oauth.client')->where('grant_type', 'personal_access');
90
91
        if (! $client->exists()) {
92
            throw new RuntimeException('Personal access client not found. Please create one.');
93
        }
94
95
        return $client->orderBy('id', 'desc')->first();
96
    }
97
98
    /**
99
     * Create a request instance for the given client.
100
     *
101
     * @param \Rinvex\Oauth\Models\Client         $client
102
     * @param \Illuminate\Database\Eloquent\Model $user
103
     * @param array                               $scopes
104
     *
105
     * @return \Psr\Http\Message\ServerRequestInterface
106
     */
107
    protected function createRequest(Client $client, Model $user, array $scopes)
108
    {
109
        $personalAccessClientSecret = config('rinvex.oauth.personal_access_client.secret');
110
111
        return (new ServerRequest('POST', 'not-important'))->withParsedBody([
112
            'grant_type' => 'personal_access',
113
            'client_id' => $client->getRouteKey(),
114
            'client_secret' => $personalAccessClientSecret,
115
            'user_id' => $user->getMorphClass().':'.$user->getRouteKey(),
116
            'scope' => implode(' ', $scopes),
117
        ]);
118
    }
119
120
    /**
121
     * Dispatch the given request to the authorization server.
122
     *
123
     * @param \Psr\Http\Message\ServerRequestInterface $request
124
     *
125
     * @throws \League\OAuth2\Server\Exception\OAuthServerException
126
     *
127
     * @return array
128
     */
129
    protected function dispatchRequestToAuthorizationServer(ServerRequestInterface $request)
130
    {
131
        return json_decode($this->server->respondToAccessTokenRequest(
132
            $request,
133
            new Response()
134
        )->getBody()->__toString(), true);
135
    }
136
137
    /**
138
     * Get the access token instance for the parsed response.
139
     *
140
     * @param array $response
141
     *
142
     * @return \Rinvex\Oauth\Models\AccessToken
143
     */
144
    protected function findAccessToken(array $response)
145
    {
146
        return app('rinvex.oauth.access_token')->where('identifier', $this->jwt->parse($response['access_token'])->getClaim('jti'));
0 ignored issues
show
Bug introduced by
The method getClaim() does not seem to exist on object<Lcobucci\JWT\Token>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
147
    }
148
}
149