JWT::encode()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 8
nc 1
nop 5
dl 0
loc 13
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Controlabs\Helper;
4
5
use Exception;
6
use DateTimeImmutable;
7
use Firebase\JWT\JWT as FirebaseJWT;
8
9
class JWT implements JWTInterface
10
{
11
    private const ALGO = 'RS256';
12
13
    private $privateKey;
14
    private $publicKey;
15
16
    public function __construct(string $privateKey = null, string $publicKey = null)
17
    {
18
        $this->privateKey = $privateKey;
19
        $this->publicKey = $publicKey;
20
    }
21
22
    /**
23
     * Generate JWT Token using private key
24
     *
25
     * @param string $iss Issuer
26
     * @param string $aud Audition
27
     * @param string $sub Subject
28
     * @param string|null $expires Expiration constraint (example: + 10 days)
29
     * @param array $claims Public claims (example: ['user_id' => 10])
30
     * @return string Returns JWT token as string
31
     * @throws Exception
32
     */
33
    public function encode(string $iss, string $aud, string $sub, string $expires = null, array $claims = []): string
34
    {
35
        $now = new DateTimeImmutable();
36
37
        $claims = array_merge($claims, [
38
            'iss' => $iss,
39
            'aud' => $aud,
40
            'sub' => $sub,
41
            'iat' => $now->getTimestamp(),
42
            'exp' => $this->expires($now, $expires)
43
        ]);
44
45
        return FirebaseJWT::encode($claims, $this->privateKey, self::ALGO);
46
    }
47
48
    /**
49
     * Decode JWT Token using public key
50
     *
51
     * @param string $token JWT Token as string
52
     * @param bool $ignoreExceptions If true will ignore any kind of exception and return null
53
     * @return array|null Returns payload as array or null if exceptions are ignored
54
     * @throws Exception
55
     */
56
    public function decode(string $token, bool $ignoreExceptions = false): ?array
57
    {
58
        try {
59
            $payload = FirebaseJWT::decode($token, $this->publicKey, [self::ALGO]);
60
61
            return json_decode(json_encode($payload), true);
62
        } catch (Exception $exception) {
63
            $this->exceptionHandler($exception, $ignoreExceptions);
64
65
            return null;
66
        }
67
    }
68
69
    /**
70
     * Extract payload of jwt token without validations
71
     *
72
     * @param string $token JWT Token as string
73
     * @return array Returns payload as array
74
     * @throws Exception
75
     */
76
    public function payload(string $token): array
77
    {
78
        $segments = $this->segments($token);
79
80
        return json_decode(
81
            FirebaseJWT::urlsafeB64Decode($segments[1]), true
82
        );
83
    }
84
85
    /**
86
     * Verify the number of segments to assert a valid token
87
     *
88
     * @param string $token
89
     * @return array
90
     * @throws Exception
91
     */
92
    protected function segments(string $token): array
93
    {
94
        $segments = explode('.', $token);
95
96
        if (3 !== count($segments)) {
97
            throw new Exception("Malformed jwt received.");
98
        }
99
100
        return $segments;
101
    }
102
103
    /**
104
     * Verify expiration contraint and return the timestamp of expiration date.
105
     * If null will return null too and token will never expire
106
     *
107
     * @param DateTimeImmutable $now
108
     * @param string|null $expires
109
     * @return int|null
110
     */
111
    protected function expires(DateTimeImmutable $now, string $expires = null)
112
    {
113
        return !$expires ? null : $now->modify($expires)->getTimestamp();
114
    }
115
116
    /**
117
     * Handle exception if $ignoreException is false
118
     *
119
     * @param Exception $exception
120
     * @param bool $ignoreException
121
     * @throws Exception
122
     */
123
    protected function exceptionHandler(Exception $exception, $ignoreException = false)
124
    {
125
        if (!$ignoreException) {
126
            throw $exception;
127
        }
128
    }
129
}
130