Skip to content

Commit

Permalink
Merge pull request #1 from RobDWaller/0.1.0-alpha1
Browse files Browse the repository at this point in the history
0.1.0 alpha1
  • Loading branch information
RobDWaller authored May 2, 2019
2 parents 44c157f + d7fe9f9 commit d02e4d1
Show file tree
Hide file tree
Showing 32 changed files with 1,143 additions and 783 deletions.
4 changes: 2 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ before_script:
- travis_retry composer install --no-interaction --prefer-source --dev

script:
- vendor/bin/phpcs --standard=psr12 src
- vendor/bin/phpstan analyse -l 7 src
- vendor/bin/phpcs --standard=psr12 src tests
- vendor/bin/phpstan analyse -l 7 src tests
- vendor/bin/phpmd src text ruleset.xml
- vendor/bin/phpunit --coverage-clover=coverage.xml

Expand Down
62 changes: 59 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,64 @@
# PSR-JWT
[![Build Status](https://travis-ci.org/RobDWaller/psr-jwt.svg?branch=master)](https://travis-ci.org/RobDWaller/psr-jwt) [![codecov](https://codecov.io/gh/RobDWaller/psr-jwt/branch/master/graph/badge.svg)](https://codecov.io/gh/RobDWaller/psr-jwt)

A PSR-7 and PSR-15 compliant JSON Web Token Middleware Library.
A PSR-7 and PSR-15 compliant JSON Web Token Middleware Library. Currently in alpha and built on top of [ReallySimpleJWT](https://github.com/RobDWaller/ReallySimpleJWT).

Currently in alpha and built on top of [ReallySimpleJWT](https://github.com/RobDWaller/ReallySimpleJWT).
The library allows you to create JSON Web Tokens and then validate them using PSR-15 compliant middleware which can be added to compatible frameworks.

For more information on JSON Web Tokens please read [RFC 7519](https://tools.ietf.org/html/rfc7519). Also to learn more about how to pass JSON Web Tokens to web applications please read up on bearer token authorization in [RFC 6750](https://tools.ietf.org/html/rfc6750).
For more information on JSON Web Tokens please read [RFC 7519](https://tools.ietf.org/html/rfc7519). Also to learn more about how to pass JSON Web Tokens to web applications please read up on bearer token authorization in [RFC 6750](https://tools.ietf.org/html/rfc6750).

## Setup

Via Composer on the command line:

```bash
composer require rbdwllr/psr-jwt
```

Via composer.json:

```javascript
"require": {
"rbdwllr/psr-jwt": "^0.1"
}
```

## Usage

PSR-JWT can be used with any PSR-7 / PSR-15 compliant framework. Just call the middleware factory method and it will return a middleware instance that exposes two methods, `__invoke()` and `process()`. The later will work with PSR-15 compliant frameworks like Zend Expressive and the former will work with older PSR-7 compliant frameworks like Slim PHP v3.

```php
\PsrJwt\Factory\JwtAuth::middleware('tokenKey', 'secret');
```

The `tokenKey` is the key required to retrieve the JSON Web Token from a cookie, query parameter or the request body. By default though the library looks for tokens in bearer field of the authorization header.

The `secret` is the string required to hash the JSON Web Token signature.

### Slim PHP 3.0 Example Implementation

```php
// Can be added to any routes file in Slim, often index.php.
$app->get('/jwt', function (Request $request, Response $response) {
$response->getBody()->write("JSON Web Token is Valid!");

return $response;
})->add(\PsrJwt\Factory\JwtAuth::middleware('jwt', 'Secret123!456$'));
```

### Zend Expressive Example Implementation

```php
// Add to the config/pipeline.php file.
$app->pipe('/api', \PsrJwt\Factory\JwtAuth::middleware('jwt', '!secReT$123*'));
```

### Generate JSON Web Token

To generate JSON Web Tokens PsrJwt offers a wrapper for the library ReallySimpleJWT. You can create an instance of the ReallySimpleJWT builder by calling the built in factory method.

```php
\PsrJwt\Factory\Jwt::builder();
```

For more information on creating tokens please read the ReallySimpleJWT documentation.
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"require-dev": {
"phpunit/phpunit": "^7.0",
"phpstan/phpstan": "^0.10",
"phpstan/phpstan-mockery": "^0.10",
"phpmd/phpmd": "2.6.*",
"squizlabs/php_codesniffer": "^3.0",
"mockery/mockery": "^1.2"
Expand Down
2 changes: 2 additions & 0 deletions phpstan.neon
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
includes:
- vendor/phpstan/phpstan-mockery/extension.neon
29 changes: 29 additions & 0 deletions src/Auth/Auth.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

declare(strict_types=1);

namespace PsrJwt\Auth;

class Auth
{
private $code;

private $message;

public function __construct(int $code, string $message)
{
$this->code = $code;

$this->message = $message;
}

public function getCode(): int
{
return $this->code;
}

public function getMessage(): string
{
return $this->message;
}
}
59 changes: 26 additions & 33 deletions src/JwtAuthHandler.php → src/Auth/Authenticate.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,16 @@

declare(strict_types=1);

namespace PsrJwt;
namespace PsrJwt\Auth;

use PsrJwt\JwtFactory;
use PsrJwt\JwtValidate;
use PsrJwt\JwtParse;
use Psr\Http\Server\RequestHandlerInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use ReallySimpleJWT\Exception\ValidateException;
use Nyholm\Psr7\Factory\Psr17Factory;
use Throwable;
use PsrJwt\Factory\Jwt;
use PsrJwt\Auth\Auth;
use PsrJwt\Parser\Parse;
use PsrJwt\Validation\Validate;

class JwtAuthHandler implements RequestHandlerInterface
class Authenticate
{
private $tokenKey;

Expand All @@ -27,16 +24,27 @@ public function __construct(string $tokenKey, string $secret)
$this->secret = $secret;
}

protected function getSecret(): string
public function authenticate(ServerRequestInterface $request): Auth
{
try {
$token = $this->getToken($request);
} catch (ValidateException $e) {
return new Auth(400, 'Bad Request: ' . $e->getMessage());
}

return $this->validate($token);
}

public function getSecret(): string
{
return $this->secret;
}

protected function validate(string $token): ResponseInterface
private function validate(string $token): Auth
{
$parse = JwtFactory::parser($token, $this->getSecret());
$parse = Jwt::parser($token, $this->getSecret());

$validate = new JwtValidate($parse);
$validate = new Validate($parse);

$validationState = $validate->validate();

Expand All @@ -48,30 +56,27 @@ protected function validate(string $token): ResponseInterface
);
}

private function validationResponse(int $code, string $message): ResponseInterface
private function validationResponse(int $code, string $message): Auth
{
$factory = new Psr17Factory();

if (in_array($code, [1, 2, 3, 4, 5], true)) {
return $factory->createResponse(401, 'Unauthorized: ' . $message);
return new Auth(401, 'Unauthorized: ' . $message);
}

return $factory->createResponse(200, 'Ok');
return new Auth(200, 'Ok');
}

private function hasJwt(string $token): bool
{
return !empty($token);
}

protected function getToken(ServerRequestInterface $request): string
private function getToken(ServerRequestInterface $request): string
{
$parse = new JwtParse(['token_key' => $this->tokenKey]);
$parse = new Parse(['token_key' => $this->tokenKey]);
$parse->addParser(\PsrJwt\Parser\Bearer::class);
$parse->addParser(\PsrJwt\Parser\Cookie::class);
$parse->addParser(\PsrJwt\Parser\Body::class);
$parse->addParser(\PsrJwt\Parser\Query::class);
$parse->addParser(\PsrJwt\Parser\Server::class);

$token = $parse->findToken($request);

Expand All @@ -81,16 +86,4 @@ protected function getToken(ServerRequestInterface $request): string

throw new ValidateException('JSON Web Token not set.', 11);
}

public function handle(ServerRequestInterface $request): ResponseInterface
{
try {
$token = $this->getToken($request);
} catch (ValidateException $e) {
$factory = new Psr17Factory();
return $factory->createResponse(400, 'Bad Request: ' . $e->getMessage());
}

return $this->validate($token);
}
}
8 changes: 4 additions & 4 deletions src/JwtFactory.php → src/Factory/Jwt.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@

declare(strict_types=1);

namespace PsrJwt;
namespace PsrJwt\Factory;

use ReallySimpleJWT\Build;
use ReallySimpleJWT\Validate;
use ReallySimpleJWT\Encode;
use ReallySimpleJWT\Parse;
use ReallySimpleJWT\Jwt;
use ReallySimpleJWT\Jwt as RSJwt;

class JwtFactory
class Jwt
{
public static function builder(): Build
{
Expand All @@ -23,7 +23,7 @@ public static function builder(): Build

public static function parser(string $token, string $secret): Parse
{
$jwt = new Jwt($token, $secret);
$jwt = new RSJwt($token, $secret);

return new Parse(
$jwt,
Expand Down
19 changes: 19 additions & 0 deletions src/Factory/JwtAuth.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

declare(strict_types=1);

namespace PsrJwt\Factory;

use PsrJwt\JwtAuthMiddleware;
use PsrJwt\Auth\Authenticate;
use PsrJwt\JwtAuthInvokable;

class JwtAuth
{
public static function middleware(string $tokenKey, string $secret): JwtAuthMiddleware
{
$auth = new Authenticate($tokenKey, $secret);

return new JwtAuthMiddleware($auth);
}
}
29 changes: 0 additions & 29 deletions src/JwtAuthFactory.php

This file was deleted.

33 changes: 0 additions & 33 deletions src/JwtAuthInvokable.php

This file was deleted.

38 changes: 37 additions & 1 deletion src/JwtAuthMiddleware.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,51 @@

namespace PsrJwt;

use Nyholm\Psr7\Factory\Psr17Factory;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
use PsrJwt\Auth\Authenticate;
use PsrJwt\Auth\Auth;

class JwtAuthMiddleware implements MiddlewareInterface
{
private $authenticate;

public function __construct(Authenticate $authenticate)
{
$this->authenticate = $authenticate;
}

public function __invoke(
ServerRequestInterface $request,
ResponseInterface $response,
callable $next
): ResponseInterface {
$auth = $this->authenticate->authenticate($request);

if ($auth->getCode() === 200) {
return $next($request, $response);
}

return $this->failResponse($auth);
}

public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
return $handler->handle($request);
$auth = $this->authenticate->authenticate($request);

if ($auth->getCode() === 200) {
return $handler->handle($request);
}

return $this->failResponse($auth);
}

private function failResponse(Auth $auth): ResponseInterface
{
$factory = new Psr17Factory();
return $factory->createResponse($auth->getCode(), $auth->getMessage());
}
}
Loading

0 comments on commit d02e4d1

Please sign in to comment.