Skip to content

Commit c3a26cc

Browse files
author
Craig Slusher
committed
Adds more flexible decode and verify as separate steps
1 parent 83b8899 commit c3a26cc

File tree

2 files changed

+55
-11
lines changed

2 files changed

+55
-11
lines changed

Authentication/JWT.php

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -43,18 +43,14 @@ class JWT
4343
*/
4444
public static function decode($jwt, $key = null, $verify = true)
4545
{
46-
$tks = explode('.', $jwt);
47-
if (count($tks) != 3) {
48-
throw new UnexpectedValueException('Wrong number of segments');
49-
}
50-
list($headb64, $bodyb64, $cryptob64) = $tks;
51-
if (null === ($header = JWT::jsonDecode(JWT::urlsafeB64Decode($headb64)))) {
46+
$tks = JWT::split($jwt);
47+
48+
if (null === ($header = JWT::jsonDecode(JWT::urlsafeB64Decode($tks['header'])))) {
5249
throw new UnexpectedValueException('Invalid header encoding');
5350
}
54-
if (null === $payload = JWT::jsonDecode(JWT::urlsafeB64Decode($bodyb64))) {
51+
if (null === $payload = JWT::jsonDecode(JWT::urlsafeB64Decode($tks['body']))) {
5552
throw new UnexpectedValueException('Invalid claims encoding');
5653
}
57-
$sig = JWT::urlsafeB64Decode($cryptob64);
5854
if ($verify) {
5955
if (empty($header->alg)) {
6056
throw new DomainException('Empty algorithm');
@@ -68,7 +64,7 @@ public static function decode($jwt, $key = null, $verify = true)
6864
}
6965

7066
// Check the signature
71-
if (!JWT::verify("$headb64.$bodyb64", $sig, $key, $header->alg)) {
67+
if (!JWT::verify($tks, $key, $header->alg)) {
7268
throw new SignatureInvalidException('Signature verification failed');
7369
}
7470

@@ -98,6 +94,31 @@ public static function decode($jwt, $key = null, $verify = true)
9894
return $payload;
9995
}
10096

97+
/**
98+
* Splits a JWT string into an array, if it isn't already split, and returns the result.
99+
*
100+
* @param object|array $payload PHP object or array
101+
* @param string|array $jwt JWT string or split tokens
102+
*
103+
* @return array A split JWT token
104+
*
105+
* @throws UnexpectedValueException Provided JWT was invalid
106+
*/
107+
public static function split($jwt)
108+
{
109+
if (is_array($jwt)) {
110+
return $jwt;
111+
}
112+
113+
$tks = explode('.', $jwt);
114+
115+
if (count($tks) != 3) {
116+
throw new UnexpectedValueException('Wrong number of segments');
117+
}
118+
119+
return array_combine(array('header', 'body', 'sig'), $tks);
120+
}
121+
101122
/**
102123
* Converts and signs a PHP object or array into a JWT string.
103124
*
@@ -161,18 +182,23 @@ public static function sign($msg, $key, $method = 'HS256')
161182
/**
162183
* Verify a signature with the mesage, key and method. Not all methods
163184
* are symmetric, so we must have a separate verify and sign method.
164-
* @param string $msg the original message
185+
* @param string $tks the split jwt token
165186
* @param string $signature
166187
* @param string|resource $key for HS*, a string key works. for RS*, must be a resource of an openssl public key
167188
* @param string $method
168189
* @return bool
169190
* @throws DomainException Invalid Algorithm or OpenSSL failure
170191
*/
171-
public static function verify($msg, $signature, $key, $method = 'HS256')
192+
public static function verify($jwt, $key, $method = 'HS256')
172193
{
173194
if (empty(self::$methods[$method])) {
174195
throw new DomainException('Algorithm not supported');
175196
}
197+
198+
$tks = JWT::split($jwt);
199+
$msg = $tks['header'] . '.' . $tks['body'];
200+
$signature = JWT::urlsafeB64Decode($tks['sig']);
201+
176202
list($function, $algo) = self::$methods[$method];
177203
switch($function) {
178204
case 'openssl':

tests/JWTTest.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,4 +116,22 @@ public function testKIDChooser()
116116
$decoded = JWT::decode($msg, $keys, true);
117117
$this->assertEquals($decoded, 'abc');
118118
}
119+
120+
public function testSplitJWT()
121+
{
122+
$msg = 'eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.Iio6aHR0cDovL2FwcGxpY2F0aW9uL2NsaWNreT9ibGFoPTEuMjMmZi5vbz00NTYgQUMwMDAgMTIzIg.E_U8X2YpMT5K1cEiT_3-IvBYfrdIFIeVYeOqre_Z5Cg';
123+
$tks = JWT::split($msg);
124+
$this->assertEquals($tks['header'], 'eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9');
125+
$this->assertEquals($tks['body'], 'Iio6aHR0cDovL2FwcGxpY2F0aW9uL2NsaWNreT9ibGFoPTEuMjMmZi5vbz00NTYgQUMwMDAgMTIzIg');
126+
$this->assertEquals($tks['sig'], 'E_U8X2YpMT5K1cEiT_3-IvBYfrdIFIeVYeOqre_Z5Cg');
127+
$tks2 = JWT::split($tks);
128+
$this->assertEquals($tks2, $tks);
129+
}
130+
131+
public function testVerify()
132+
{
133+
$msg = 'eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.Iio6aHR0cDovL2FwcGxpY2F0aW9uL2NsaWNreT9ibGFoPTEuMjMmZi5vbz00NTYgQUMwMDAgMTIzIg.E_U8X2YpMT5K1cEiT_3-IvBYfrdIFIeVYeOqre_Z5Cg';
134+
$tks = JWT::split($msg);
135+
$this->assertTrue(JWT::verify($tks, 'my_key'));
136+
}
119137
}

0 commit comments

Comments
 (0)