Skip to content

Commit 18bc1f1

Browse files
committed
Merge branch 'master' of github.com:mevdschee/php-crud-api
2 parents 909edd7 + f4dbf3b commit 18bc1f1

File tree

5 files changed

+85
-9
lines changed

5 files changed

+85
-9
lines changed

README.md

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -162,9 +162,13 @@ You can tune the middleware behavior using middleware specific configuration par
162162
- "cors.allowCredentials": To allow credentials in the CORS request ("true")
163163
- "cors.maxAge": The time that the CORS grant is valid in seconds ("1728000")
164164
- "jwtAuth.mode": Set to "optional" if you want to allow anonymous access ("required")
165+
- "jwtAuth.header": Name of the header containing the JWT token ("X-Authorization")
165166
- "jwtAuth.leeway": The acceptable number of seconds of clock skew ("5")
166167
- "jwtAuth.ttl": The number of seconds the token is valid ("30")
167168
- "jwtAuth.secret": The shared secret used to sign the JWT token with ("")
169+
- "jwtAuth.algorithms": The algorithms that are allowed, empty means 'all' ("")
170+
- "jwtAuth.audiences": The audiences that are allowed, empty means 'all' ("")
171+
- "jwtAuth.issuers": The issuers that are allowed, empty means 'all' ("")
168172
- "basicAuth.mode": Set to "optional" if you want to allow anonymous access ("required")
169173
- "basicAuth.realm": Text to prompt when showing login ("Username and password required")
170174
- "basicAuth.passwordFile": The file to read for username/password combinations (".htpasswd")
@@ -585,10 +589,12 @@ This example sends the string "username1:password1".
585589

586590
The JWT type requires another (SSO/Identity) server to sign a token that contains claims.
587591
Both servers share a secret so that they can either sign or verify that the signature is valid.
588-
Claims are stored in the `$_SESSION['claims']` variable.
589-
You need to send an "Authorization" header containing a base64 url encoded and dot separated token header, body and signature after the word "Bearer" ([read more about JWT here](https://jwt.io/)).
592+
Claims are stored in the `$_SESSION['claims']` variable. You need to send an "X-Authorization"
593+
header containing a base64 url encoded and dot separated token header, body and signature after
594+
the word "Bearer" ([read more about JWT here](https://jwt.io/)). The standard says you need to
595+
use the "Authorization" header, but this is problematic in Apache and PHP.
590596

591-
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6IjE1MzgyMDc2MDUiLCJleHAiOjE1MzgyMDc2MzV9.Z5px_GT15TRKhJCTHhDt5Z6K6LRDSFnLj8U5ok9l7gw
597+
X-Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6IjE1MzgyMDc2MDUiLCJleHAiOjE1MzgyMDc2MzV9.Z5px_GT15TRKhJCTHhDt5Z6K6LRDSFnLj8U5ok9l7gw
592598

593599
This example sends the signed claims:
594600

api.php

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3261,7 +3261,7 @@ public function handle(Request $request): Response
32613261

32623262
class JwtAuthMiddleware extends Middleware
32633263
{
3264-
private function getVerifiedClaims(String $token, int $time, int $leeway, int $ttl, String $secret): array
3264+
private function getVerifiedClaims(String $token, int $time, int $leeway, int $ttl, String $secret, array $requirements): array
32653265
{
32663266
$algorithms = array('HS256' => 'sha256', 'HS384' => 'sha384', 'HS512' => 'sha512');
32673267
$token = explode('.', $token);
@@ -3288,6 +3288,13 @@ private function getVerifiedClaims(String $token, int $time, int $leeway, int $t
32883288
if (!$claims) {
32893289
return array();
32903290
}
3291+
foreach ($requirements as $field => $values) {
3292+
if (!empty($values)) {
3293+
if (!isset($claims[$field]) || !in_array($claims[$field], $values)) {
3294+
return array();
3295+
}
3296+
}
3297+
}
32913298
if (isset($claims['nbf']) && $time + $leeway < $claims['nbf']) {
32923299
return array();
32933300
}
@@ -3305,21 +3312,32 @@ private function getVerifiedClaims(String $token, int $time, int $leeway, int $t
33053312
return $claims;
33063313
}
33073314

3315+
private function getArrayProperty(String $property, String $default): array
3316+
{
3317+
return array_filter(array_map('trim', explode(',', $this->getProperty($property, $default))));
3318+
}
3319+
33083320
private function getClaims(String $token): array
33093321
{
33103322
$time = (int) $this->getProperty('time', time());
33113323
$leeway = (int) $this->getProperty('leeway', '5');
33123324
$ttl = (int) $this->getProperty('ttl', '30');
33133325
$secret = $this->getProperty('secret', '');
3326+
$requirements = array(
3327+
'alg' => $this->getArrayProperty('algorithms', ''),
3328+
'aud' => $this->getArrayProperty('audiences', ''),
3329+
'iss' => $this->getArrayProperty('issuers', ''),
3330+
);
33143331
if (!$secret) {
33153332
return array();
33163333
}
3317-
return $this->getVerifiedClaims($token, $time, $leeway, $ttl, $secret);
3334+
return $this->getVerifiedClaims($token, $time, $leeway, $ttl, $secret, $requirements);
33183335
}
33193336

33203337
private function getAuthorizationToken(Request $request): String
33213338
{
3322-
$parts = explode(' ', trim($request->getHeader('Authorization')), 2);
3339+
$header = $this->getProperty('header', 'X-Authorization');
3340+
$parts = explode(' ', trim($request->getHeader($header)), 2);
33233341
if (count($parts) != 2) {
33243342
return '';
33253343
}

examples/clients/auth0/vanilla.html

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<html>
2+
<head>
3+
<meta charset="utf-8" />
4+
<script>
5+
var domain = ''; // hostname ending in '.auth0.com'
6+
var clientId = ''; // client id as defined in auth0
7+
var audience = ''; // api audience as defined in auth0
8+
window.onload = function () {
9+
var match = RegExp('[#&]access_token=([^&]*)').exec(window.location.hash);
10+
var accessToken = match && decodeURIComponent(match[1].replace(/\+/g, ' '));
11+
if (!accessToken) {
12+
document.location = 'https://'+domain+'/authorize?audience='+audience+'&response_type=token&client_id='+clientId+'&redirect_uri='+document.location.href;
13+
} else {
14+
document.location.hash = '';
15+
var req = new XMLHttpRequest();
16+
req.onreadystatechange = function () {
17+
if (req.readyState==4) {
18+
console.log(req.responseText);
19+
document.getElementById('output').innerHTML = JSON.stringify(JSON.parse(req.responseText), undefined, 4);
20+
}
21+
}
22+
url = '/api.php/records/posts?join=categories&join=tags&join=comments&filter=id,eq,1';
23+
req.open("GET", url, true);
24+
req.setRequestHeader('X-Authorization', 'Bearer '+accessToken);
25+
req.send();
26+
}
27+
};
28+
</script>
29+
</head>
30+
<body>
31+
<pre id="output"></pre>
32+
</body>
33+
</html>

examples/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
<body>
66
<h1>Example clients</h1>
77
<ul>
8+
<li><a href="/examples/clients/auth0/vanilla.html">Auth0 + VanillaJS</a></li>
89
<li><a href="/examples/clients/vanilla.html">VanillaJS</a></li>
910
<li><a href="/examples/clients/angular.html">Angular</a></li>
1011
<li><a href="/examples/clients/angular2.html">Angular 2</a></li>

src/Tqdev/PhpCrudApi/Middleware/JwtAuthMiddleware.php

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
class JwtAuthMiddleware extends Middleware
1111
{
12-
private function getVerifiedClaims(String $token, int $time, int $leeway, int $ttl, String $secret): array
12+
private function getVerifiedClaims(String $token, int $time, int $leeway, int $ttl, String $secret, array $requirements): array
1313
{
1414
$algorithms = array('HS256' => 'sha256', 'HS384' => 'sha384', 'HS512' => 'sha512');
1515
$token = explode('.', $token);
@@ -36,6 +36,13 @@ private function getVerifiedClaims(String $token, int $time, int $leeway, int $t
3636
if (!$claims) {
3737
return array();
3838
}
39+
foreach ($requirements as $field => $values) {
40+
if (!empty($values)) {
41+
if (!isset($claims[$field]) || !in_array($claims[$field], $values)) {
42+
return array();
43+
}
44+
}
45+
}
3946
if (isset($claims['nbf']) && $time + $leeway < $claims['nbf']) {
4047
return array();
4148
}
@@ -53,21 +60,32 @@ private function getVerifiedClaims(String $token, int $time, int $leeway, int $t
5360
return $claims;
5461
}
5562

63+
private function getArrayProperty(String $property, String $default): array
64+
{
65+
return array_filter(array_map('trim', explode(',', $this->getProperty($property, $default))));
66+
}
67+
5668
private function getClaims(String $token): array
5769
{
5870
$time = (int) $this->getProperty('time', time());
5971
$leeway = (int) $this->getProperty('leeway', '5');
6072
$ttl = (int) $this->getProperty('ttl', '30');
6173
$secret = $this->getProperty('secret', '');
74+
$requirements = array(
75+
'alg' => $this->getArrayProperty('algorithms', ''),
76+
'aud' => $this->getArrayProperty('audiences', ''),
77+
'iss' => $this->getArrayProperty('issuers', ''),
78+
);
6279
if (!$secret) {
6380
return array();
6481
}
65-
return $this->getVerifiedClaims($token, $time, $leeway, $ttl, $secret);
82+
return $this->getVerifiedClaims($token, $time, $leeway, $ttl, $secret, $requirements);
6683
}
6784

6885
private function getAuthorizationToken(Request $request): String
6986
{
70-
$parts = explode(' ', trim($request->getHeader('Authorization')), 2);
87+
$header = $this->getProperty('header', 'X-Authorization');
88+
$parts = explode(' ', trim($request->getHeader($header)), 2);
7189
if (count($parts) != 2) {
7290
return '';
7391
}

0 commit comments

Comments
 (0)