RobDWaller / ReallySimpleJWT
1
<?php
2

3
declare(strict_types=1);
4

5
namespace ReallySimpleJWT;
6

7
use ReallySimpleJWT\Interfaces\Validator;
8
use ReallySimpleJWT\Interfaces\Encode;
9
use ReallySimpleJWT\Jwt;
10
use ReallySimpleJWT\Interfaces\Secret;
11
use ReallySimpleJWT\Exception\BuildException;
12

13
/**
14
 * A class to help build a JSON Web Token.
15
 *
16
 * Class contains helper methods that allow you to easily set JWT claims
17
 * defined in the JWT RFC. Eg setIssuer() will set the iss claim in the
18
 * JWT payload.
19
 */
20
class Build
21
{
22
    /**
23
     * Defines the type of JWT to be created, usually just JWT.
24
     */
25
    private string $type;
26

27
    /**
28
     * Holds the JWT header claims
29
     *
30
     * @var mixed[]
31
     */
32
    private array $header = [];
33

34
    /**
35
     * Holds the JWT payload claims.
36
     *
37
     * @var mixed[]
38
     */
39
    private array $payload = [];
40

41
    /**
42
     * The secret string for encoding the JWT signature.
43
     */
44
    private string $secret = '';
45

46
    /**
47
     * Token claim validator.
48
     */
49
    private Validator $validate;
50

51
    /**
52
     * Signature secret validator.
53
     */
54
    private Secret $secretValidator;
55

56
    /**
57
     * Token Encoder which complies with the encoder interface.
58
     */
59
    private Encode $encode;
60

61 16
    public function __construct(string $type, Validator $validate, Secret $secretValidator, Encode $encode)
62
    {
63 16
        $this->type = $type;
64

65 16
        $this->validate = $validate;
66

67 16
        $this->secretValidator =  $secretValidator;
68

69 16
        $this->encode = $encode;
70
    }
71

72
    /**
73
     * Define the content type header claim for the JWT. This defines
74
     * structural information about the token. For instance if it is a
75
     * nested token.
76
     */
77 16
    public function setContentType(string $contentType): Build
78
    {
79 16
        $this->header['cty'] = $contentType;
80

81 16
        return $this;
82
    }
83

84
    /**
85
     * Add custom claims to the JWT header
86
     *
87
     * @param mixed $value
88
     */
89 16
    public function setHeaderClaim(string $key, $value): Build
90
    {
91 16
        $this->header[$key] = $value;
92

93 16
        return $this;
94
    }
95

96
    /**
97
     * Get the contents of the JWT header. This is an associative array of
98
     * the defined header claims. The JWT algorithm and typ are added
99
     * by default.
100
     *
101
     * @return mixed[]
102
     */
103 16
    public function getHeader(): array
104
    {
105 16
        return array_merge(
106 16
            $this->header,
107 16
            ['alg' => $this->encode->getAlgorithm(), 'typ' => $this->type]
108
        );
109
    }
110

111
    /**
112
     * Set the JWT secret for encrypting the JWT signature. The secret must
113
     * comply with the validation rules defined in the
114
     * ReallySimpleJWT\Secret class.
115
     *
116
     * @throws BuildException
117
     */
118 16
    public function setSecret(string $secret): Build
119
    {
120 16
        if (!$this->secretValidator->validate($secret)) {
121 16
            throw new BuildException('Invalid secret.', 9);
122
        }
123

124 16
        $this->secret = $secret;
125

126 16
        return $this;
127
    }
128

129
    /**
130
     * Set the issuer JWT payload claim. This defines who issued the token.
131
     * Can be a string or URI.
132
     */
133 16
    public function setIssuer(string $issuer): Build
134
    {
135 16
        $this->payload['iss'] = $issuer;
136

137 16
        return $this;
138
    }
139

140
    /**
141
     * Set the subject JWT payload claim. This defines who the JWT is for.
142
     * Eg an application user or admin.
143
     */
144 16
    public function setSubject(string $subject): Build
145
    {
146 16
        $this->payload['sub'] = $subject;
147

148 16
        return $this;
149
    }
150

151
    /**
152
     * Set the audience JWT payload claim. This defines a list of 'principals'
153
     * who will process the JWT. Eg a website or websites who will validate
154
     * users who use this token. This claim can either be a single string or an
155
     * array of strings.
156
     *
157
     * @param mixed $audience
158
     * @throws BuildException
159
     */
160 16
    public function setAudience($audience): Build
161
    {
162 16
        if (is_string($audience) || is_array($audience)) {
163 16
            $this->payload['aud'] = $audience;
164

165 16
            return $this;
166
        }
167

168 16
        throw new BuildException('Invalid Audience claim.', 10);
169
    }
170

171
    /**
172
     * Set the expiration JWT payload claim. This sets the time at which the
173
     * JWT should expire and no longer be accepted.
174
     *
175
     * @throws BuildException
176
     */
177 16
    public function setExpiration(int $timestamp): Build
178
    {
179 16
        if (!$this->validate->expiration($timestamp)) {
180 16
            throw new BuildException('Expiration claim has expired.', 4);
181
        }
182

183 16
        $this->payload['exp'] = $timestamp;
184

185 16
        return $this;
186
    }
187

188
    /**
189
     * Set the not before JWT payload claim. This sets the time after which the
190
     * JWT can be accepted.
191
     */
192 16
    public function setNotBefore(int $notBefore): Build
193
    {
194 16
        $this->payload['nbf'] = $notBefore;
195

196 16
        return $this;
197
    }
198

199
    /**
200
     * Set the issued at JWT payload claim. This sets the time at which the
201
     * JWT was issued / created.
202
     */
203 16
    public function setIssuedAt(int $issuedAt): Build
204
    {
205 16
        $this->payload['iat'] = $issuedAt;
206

207 16
        return $this;
208
    }
209

210
    /**
211
     * Set the JSON token identifier JWT payload claim. This defines a unique
212
     * identifier for the token.
213
     */
214 16
    public function setJwtId(string $jwtId): Build
215
    {
216 16
        $this->payload['jti'] = $jwtId;
217

218 16
        return $this;
219
    }
220

221
    /**
222
     * Set a custom payload claim on the JWT. The RFC calls these private
223
     * claims. Eg you may wish to set a user_id or a username in the
224
     * JWT payload.
225
     *
226
     * @param mixed $value
227
     */
228 16
    public function setPayloadClaim(string $key, $value): Build
229
    {
230 16
        $this->payload[$key] = $value;
231

232 16
        return $this;
233
    }
234

235
    /**
236
     * Get the JWT payload. This will return an array of registered claims and
237
     * private claims which make up the JWT payload.
238
     *
239
     * @return mixed[]
240
     */
241 16
    public function getPayload(): array
242
    {
243 16
        return $this->payload;
244
    }
245

246
    /**
247
     * Build the token, this is the last method which should be called after
248
     * all the header and payload claims have been set. It will encode the
249
     * header and payload, and generate the JWT signature. It will then
250
     * concatenate each part with dots into a single string.
251
     *
252
     * This JWT string along with the secret are then used to generate a new
253
     * instance of the JWT class which is returned.
254
     */
255 16
    public function build(): Jwt
256
    {
257 16
        return new Jwt(
258 16
            $this->encode->encode($this->getHeader()) . "." .
259 16
            $this->encode->encode($this->getPayload()) . "." .
260 16
            $this->getSignature(),
261 16
            $this->secret
262
        );
263
    }
264

265
    /**
266
     * Generate a new token with the same initial setup. Allows you to chain the
267
     * creation of multiple tokens.
268
     */
269 16
    public function reset(): Build
270
    {
271 16
        return new Build(
272 16
            $this->type,
273 16
            $this->validate,
274 16
            $this->secretValidator,
275 16
            $this->encode
276
        );
277
    }
278

279
    /**
280
     * Generate and return the JWT signature, this is made up of the header,
281
     * payload and secret.
282
     *
283
     * @throws BuildException
284
     */
285 16
    private function getSignature(): string
286
    {
287 16
        if ($this->secretValidator->validate($this->secret)) {
288 16
            return $this->encode->signature(
289 16
                $this->getHeader(),
290 16
                $this->getPayload(),
291 16
                $this->secret
292
            );
293
        }
294

295 16
        throw new BuildException('Invalid secret.', 9);
296
    }
297
}

Read our documentation on viewing source code .

Loading