Passed
Branch master (24feaf)
by Ion
02:29
created

Jwt::generateSignature()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 4
c 0
b 0
f 0
dl 0
loc 9
rs 10
cc 2
nc 2
nop 3
1
<?php
2
3
namespace IonGhitun\JwtToken;
4
5
use Carbon\Carbon;
6
use IonGhitun\JwtToken\Exceptions\JwtException;
7
8
/**
9
 * Class Jwt
10
 *
11
 * @package IonGhitun\JwtToken
12
 */
13
class Jwt
14
{
15
    /**
16
     * Generate a new JWT token.
17
     *
18
     * @param array $payload
19
     *
20
     * @return string
21
     *
22
     * @throws JwtException
23
     */
24
    public static function generateToken(array $payload)
25
    {
26
        try {
27
            $header = self::base64EncodeUrlSafe(json_encode(['typ' => 'JWT', 'alg' => 'HS256']));
28
29
            if (!isset($payload['expiration'])) {
30
                $payload['expiration'] = Carbon::now()->addDay()->format('Y-m-d H:i:s');
31
            }
32
33
            $payload = self::base64EncodeUrlSafe(json_encode($payload));
34
            $signature = self::generateSignature($header, $payload);
35
36
            return $header . "." . $payload . "." . $signature;
37
        } catch (\Exception $e) {
38
            throw new JwtException($e->getMessage(), $e->getCode());
39
        }
40
    }
41
42
    /**
43
     * Url safe base 64 encode.
44
     *
45
     * @param string $string
46
     *
47
     * @return string|string[]
48
     */
49
    private static function base64EncodeUrlSafe(string $string)
50
    {
51
        return str_replace('=', '', strtr(base64_encode($string), '+/', '-_'));
52
    }
53
54
    /**
55
     * Generate signature
56
     *
57
     * @param $header
58
     * @param $payload
59
     * @param bool $encode
60
     *
61
     * @return string|string[]
62
     */
63
    private static function generateSignature($header, $payload, $encode = true)
64
    {
65
        $signature = hash_hmac('sha256', $header . '.' . $payload, getenv('JWT_SECRET'), true);
66
67
        if ($encode) {
68
            return self::base64EncodeUrlSafe($signature);
69
        }
70
71
        return $signature;
72
    }
73
74
    /**
75
     * Validate JWT token and return payload
76
     *
77
     * @param $token
78
     *
79
     * @return mixed
80
     *
81
     * @throws JwtException
82
     */
83
    public static function validateToken($token)
84
    {
85
        try {
86
            $tokenData = explode('.', $token);
87
88
            if (count($tokenData) !== 3) {
89
                throw new JwtException('Not a valid JWT token!');
90
            }
91
92
            list($header64, $payload64, $signature64) = $tokenData;
93
94
            $header = json_decode(self::base64DecodeUrlSafe($header64), true);
95
            $payload = json_decode(self::base64DecodeUrlSafe($payload64), true);
96
97
            if (!$header || !$payload || !isset($payload['expiration'])) {
98
                throw new JwtException('Not a valid JWT token!');
99
            }
100
101
            if (Carbon::parse($payload['expiration']) < Carbon::now()) {
102
                throw new JwtException('Jwt token expired!');
103
            }
104
105
            $signature = self::base64DecodeUrlSafe($signature64);
106
107
            if ($signature !== self::generateSignature($header64, $payload64, false)) {
108
                throw new JwtException('Could not verify Jwt token signature!');
109
            }
110
111
            return $payload;
112
        } catch (\Exception $e) {
113
            throw new JwtException($e->getMessage(), $e->getCode());
114
        }
115
    }
116
117
    /**
118
     * Url safe base 64 decode.
119
     *
120
     * @param $string
121
     *
122
     * @return false|string
123
     */
124
    private static function base64DecodeUrlSafe($string)
125
    {
126
        $mod = strlen($string) % 4;
127
128
        if ($mod !== 0) {
129
            $padlen = 4 - $mod;
130
            $string .= str_repeat('=', $padlen);
131
        }
132
133
        return base64_decode(strtr($string, '-_', '+/'));
134
    }
135
}
136