aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/bshaffer/oauth2-server-php/src/OAuth2/ResponseType/JwtAccessToken.php
blob: 0af9705ff3ab8e5f8a62d847b3c263787b87910e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
<?php

namespace OAuth2\ResponseType;

use OAuth2\Encryption\EncryptionInterface;
use OAuth2\Encryption\Jwt;
use OAuth2\Storage\AccessTokenInterface as AccessTokenStorageInterface;
use OAuth2\Storage\RefreshTokenInterface;
use OAuth2\Storage\PublicKeyInterface;
use OAuth2\Storage\Memory;

/**
 * @author Brent Shaffer <bshafs at gmail dot com>
 */
class JwtAccessToken extends AccessToken
{
    protected $publicKeyStorage;
    protected $encryptionUtil;

    /**
     * @param PublicKeyInterface          $publicKeyStorage -
     * @param AccessTokenStorageInterface $tokenStorage     -
     * @param RefreshTokenInterface       $refreshStorage   -
     * @param array                       $config           - array with key store_encrypted_token_string (bool true)
     *                                                        whether the entire encrypted string is stored,
     *                                                        or just the token ID is stored
     * @param EncryptionInterface         $encryptionUtil   -
     */
    public function __construct(PublicKeyInterface $publicKeyStorage = null, AccessTokenStorageInterface $tokenStorage = null, RefreshTokenInterface $refreshStorage = null, array $config = array(), EncryptionInterface $encryptionUtil = null)
    {
        $this->publicKeyStorage = $publicKeyStorage;
        $config = array_merge(array(
            'store_encrypted_token_string' => true,
            'issuer' => ''
        ), $config);
        if (is_null($tokenStorage)) {
            // a pass-thru, so we can call the parent constructor
            $tokenStorage = new Memory();
        }
        if (is_null($encryptionUtil)) {
            $encryptionUtil = new Jwt();
        }
        $this->encryptionUtil = $encryptionUtil;
        parent::__construct($tokenStorage, $refreshStorage, $config);
    }

    /**
     * Handle the creation of access token, also issue refresh token if supported / desirable.
     *
     * @param mixed  $client_id           - Client identifier related to the access token.
     * @param mixed  $user_id             - User ID associated with the access token
     * @param string $scope               - (optional) Scopes to be stored in space-separated string.
     * @param bool   $includeRefreshToken - If true, a new refresh_token will be added to the response
     * @return array                      - The access token
     *
     * @see http://tools.ietf.org/html/rfc6749#section-5
     * @ingroup oauth2_section_5
     */
    public function createAccessToken($client_id, $user_id, $scope = null, $includeRefreshToken = true)
    {
        // payload to encrypt
        $payload = $this->createPayload($client_id, $user_id, $scope);

        /*
         * Encode the payload data into a single JWT access_token string
         */
        $access_token = $this->encodeToken($payload, $client_id);

        /*
         * Save the token to a secondary storage.  This is implemented on the
         * OAuth2\Storage\JwtAccessToken side, and will not actually store anything,
         * if no secondary storage has been supplied
         */
        $token_to_store = $this->config['store_encrypted_token_string'] ? $access_token : $payload['id'];
        $this->tokenStorage->setAccessToken($token_to_store, $client_id, $user_id, $this->config['access_lifetime'] ? time() + $this->config['access_lifetime'] : null, $scope);

        // token to return to the client
        $token = array(
            'access_token' => $access_token,
            'expires_in' => $this->config['access_lifetime'],
            'token_type' => $this->config['token_type'],
            'scope' => $scope
        );

        /*
         * Issue a refresh token also, if we support them
         *
         * Refresh Tokens are considered supported if an instance of OAuth2\Storage\RefreshTokenInterface
         * is supplied in the constructor
         */
        if ($includeRefreshToken && $this->refreshStorage) {
            $refresh_token = $this->generateRefreshToken();
            $expires = 0;
            if ($this->config['refresh_token_lifetime'] > 0) {
                $expires = time() + $this->config['refresh_token_lifetime'];
            }
            $this->refreshStorage->setRefreshToken($refresh_token, $client_id, $user_id, $expires, $scope);
            $token['refresh_token'] = $refresh_token;
        }

        return $token;
    }

    /**
     * @param array $token
     * @param mixed $client_id
     * @return mixed
     */
    protected function encodeToken(array $token, $client_id = null)
    {
        $private_key = $this->publicKeyStorage->getPrivateKey($client_id);
        $algorithm   = $this->publicKeyStorage->getEncryptionAlgorithm($client_id);

        return $this->encryptionUtil->encode($token, $private_key, $algorithm);
    }

    /**
     * This function can be used to create custom JWT payloads
     *
     * @param mixed  $client_id           - Client identifier related to the access token.
     * @param mixed  $user_id             - User ID associated with the access token
     * @param string $scope               - (optional) Scopes to be stored in space-separated string.
     * @return array                      - The access token
     */
    protected function createPayload($client_id, $user_id, $scope = null)
    {
        // token to encrypt
        $expires = time() + $this->config['access_lifetime'];
        $id = $this->generateAccessToken();

        return array(
            'id'         => $id, // for BC (see #591)
            'jti'        => $id,
            'iss'        => $this->config['issuer'],
            'aud'        => $client_id,
            'sub'        => $user_id,
            'exp'        => $expires,
            'iat'        => time(),
            'token_type' => $this->config['token_type'],
            'scope'      => $scope
        );
    }
}