Giter Club home page Giter Club logo

phalcon-auth-jwt's Introduction

Phalcon JWT Auth

Example micro app sinbadxiii/phalcon-auth-jwt-example

Additional JWT guard for the Phalcon authentication library sinbadxiii/phalcon-auth

Banner

Software License Packagist Downloads Latest Version

Demo

Banner

Requirements

Phalcon: ^5

PHP: ^7.4 || ^8.1

Installation

Install via composer

Run the following command to pull in the latest version::

composer require "sinbadxiii/phalcon-auth-jwt"

Add service provider

use Sinbadxiii\PhalconAuthJWT\Blacklist;
use Sinbadxiii\PhalconAuthJWT\Builder;
use Sinbadxiii\PhalconAuthJWT\Http\Parser\Chains\AuthHeaders;
use Sinbadxiii\PhalconAuthJWT\Http\Parser\Chains\InputSource;
use Sinbadxiii\PhalconAuthJWT\Http\Parser\Chains\QueryString;
use Sinbadxiii\PhalconAuthJWT\Http\Parser\Parser;
use Sinbadxiii\PhalconAuthJWT\JWT;
use Sinbadxiii\PhalconAuthJWT\Manager as JWTManager;


$di->setShared("jwt", function () {

    $configJwt = $this->getConfig()->path('jwt');

    $providerJwt = $configJwt->providers->jwt;

    $builder = new Builder();

    $builder->lockSubject($configJwt->lock_subject)
        ->setTTL($configJwt->ttl)
        ->setRequiredClaims($configJwt->required_claims->toArray())
        ->setLeeway($configJwt->leeway)
        ->setMaxRefreshPeriod($configJwt->max_refresh_period);

    $parser = new Parser($this->getRequest(), [
        new AuthHeaders,
        new QueryString,
        new InputSource,
    ]);

    $providerStorage = $configJwt->providers->storage;

    $blacklist = new Blacklist(new $providerStorage($this->getCache()));

    $blacklist->setGracePeriod($configJwt->blacklist_grace_period);

    $manager = new JWTManager(new $providerJwt(
        $configJwt->secret,
        $configJwt->algo,
        $configJwt->keys->toArray()
    ), $blacklist, $builder);

    $manager->setBlacklistEnabled((bool) $configJwt->blacklist_enabled);

    return new JWT($builder, $manager, $parser);
});

Configuration

Copy file from config/jwt.php in your folder config and merge your config

Generate secret key

Update the secret value in config jwt.php or JWT_SECRET value in your .env file.

Generate a 32 character secret phrase like here https://passwordsgenerator.net/

Update your User model

Firstly you need to implement the Sinbadxiii\PhalconAuthJWT\JWTSubject contract on your User model, which requires that you implement the 2 methods getJWTIdentifier() and getJWTCustomClaims().

The example below:

<?php

namespace App\Models;

use Phalcon\Mvc\Model;
use Sinbadxiii\PhalconAuthJWT\JWTSubject;

class User extends Model implements JWTSubject
{

    //...
    
    public function getJWTIdentifier()
    {
        return $this->id;
    }

    public function getJWTCustomClaims()
    {
        return [
            "email" => $this->email,
            "username" => $this->username
        ];
    }
}

Create auth access, for example "jwt"

<?php

namespace App\Security\Access;

use Sinbadxiii\PhalconAuth\Access\AbstractAccess;

class Jwt extends AbstractAccess
{
    /**
     * @return bool
     */
    public function allowedIf(): bool
    {
        return $this->auth->parseToken()->check();
    }
}

Set as a guard JWT

$di->setShared("auth", function () {

    $security = $this->getSecurity();

    $adapter     = new \Sinbadxiii\PhalconAuth\Adapter\Model($security);
    $adapter->setModel(App\Models\User::class);

    $guard = new \Sinbadxiii\PhalconAuthJWT\Guard\JWTGuard(
        $adapter,
        $this->getJwt(),
        $this->getRequest(),
        $this->getEventsManager(),
    );

    $manager = new Manager();
    $manager->addGuard("jwt", $guard);
    $manager->setDefaultGuard($guard);

    $manager->setAccess(new \App\Security\Access\Jwt());
    $manager->except("/auth/login");

    return $manager;
});

Here we are telling the api guard to use the jwt driver, and we are setting the api guard as the default.

We can now use Phalcon Auth with JWT guard.

Add some basic handlers

    $application = new \Phalcon\Mvc\Micro($di);

    $eventsManager = new Manager();
   
    $application->post(
        "/auth/logout",
        function () {
            $this->auth->logout();

            return ['message' => 'Successfully logged out'];
        }
    );

    $application->post(
        "/auth/refresh",
        function () {
            $token = $this->auth->refresh();

            return $token->toResponse();
        }
    );

    $application->post(
        '/auth/login',
        function () {

            $credentials = [
                'email' => $this->request->getJsonRawBody()->email,
                'password' => $this->request->getJsonRawBody()->password
            ];

            $this->auth->claims(['aud' => [
                $this->request->getURI()
            ]]);

            if (! $token = $this->auth->attempt($credentials)) {
                return ['error' => 'Unauthorized'];
            }

            return $token->toResponse();
        }
    );

    $application->get(
        '/',
        function () {
            return [
                'message' => 'hello, my friend'
            ];
        }
    );
        

Example Auth Login Controller

<?php

declare(strict_types=1);

namespace App\Controllers\Auth;

use Phalcon\Mvc\Controller;

class LoginController extends Controller
{
    public function loginAction()
    {
        $credentials = [
            'email' => $this->request->getJsonRawBody()->email,
            'password' => $this->request->getJsonRawBody()->password
        ];

        $this->auth->claims(['aud' => [
            $this->request->getURI()
        ]]);

        if (! $token = $this->auth->attempt($credentials)) {
            $this->response->setJsonContent(['error' => 'Unauthorized'])->send();
        }

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

    public function meAction()
    {
        $this->response->setJsonContent($this->auth->user())->send();
    }

    public function logoutAction()
    {
        $this->auth->logout();

        $this->response->setJsonContent(['message' => 'Successfully logged out'])->send();
    }

    public function refreshAction()
    {
         return $this->respondWithToken($this->auth->refresh());
    }

    protected function respondWithToken($token)
    {
        $this->response->setJsonContent($token->toResponse())->send();
    }
}

Attach Middleware

Example code for middleware:

<?php

namespace App\Middlewares;

use Phalcon\Mvc\Micro\MiddlewareInterface;
use Phalcon\Mvc\Micro;

use function in_array;

class AuthMiddleware implements MiddlewareInterface
{
    public function call(Micro $application)
    {
        $authService = $application->getDI()->get("auth");

        if ($access = $authService->getAccess()) {
            $excepts = $access->getExceptActions();

            $uri = $application->getDI()->get("request")->getURI(true);

            if (!in_array($uri, $excepts)) {
                try {
                     $authService->parseToken()->checkOrFail();
                } catch (\Throwable $t) {
                    $responseService = $application->getDI()->get("response");
                    $responseService->setStatusCode(401, 'Unauthorized');
                    $responseService->setJsonContent(
                        [
                            "error" => "Unauthorized: " . $t->getMessage(),
                            "code" => 401
                        ]
                    );
                    if (!$responseService->isSent()) {
                        $responseService->send();
                    }
                }
            }
        }

        return true;
    }
}

and attach:

$application = new \Phalcon\Mvc\Micro($di);

$eventsManager = new Manager();

$eventsManager->attach('micro', new AuthMiddleware());
$application->before(new AuthMiddleware());

You should now be able to POST to the login endpoint (e.g. http://0.0.0.0:8000/auth/login) with some valid credentials and see a response like:

{
    "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJhdWQiOlsiXC9hdXRoXC9sb2dpbiJdLCJleHAiOjE2MzE2OTkwOTMsImlzcyI6IjAuMC4wLjA6ODAwMCIsImlhdCI6MTYzMTY5NzI5MywianRpIjoiZFNhaGhyeUciLCJzdWIiOiIzIiwiZW1haWwiOiIxMjM0NUAxMjM0NS5ydSIsInVzZXJuYW1lIjoiMTIzNDUgdXNlcm5hbWUifQ.bTyngpVQt86IwtySdRUxPgZH_xk-44hYHTkmiA3BC_0s75TvkuLqTC9WN1jzBIR7Q_H4dWb_ErPR2MlTaw9VQA",
    "token_type": "bearer",
    "expires_in": 1800
}

There are a number of ways to send the token via http:

Authorization header:

Authorization Bearer eyJ0eXAiOiJKV1QiLC...

Query string param:

http://0.0.0.0:8000/me?token=eyJ0eXAiOiJKV1QiLC...

Exceptions

Methods

Multiple Guards

$credentials = ['email' => '[email protected]', 'password' => '1234'];

$token = $this->auth->guard('api')->attempt($credentials);

attempt()

Attempt to authenticate a user via some credentials.

// Generate a token for the user if the credentials are valid
$token = $this->auth->attempt($credentials);

This will return either a jwt or null

login()

Log a user in and return a jwt for them.

// Get some user from somewhere
$user = User::findFirst(1);

// Get the token
$token = $this->auth->login($user);

user()

Get the currently authenticated user.

// Get the currently authenticated user
$user =  $this->auth->user();

If the user is not then authenticated, then null will be returned.

logout()

Log the user out - which will invalidate the current token and unset the authenticated user.

$this->auth->logout();

refresh()

Refresh a token, which invalidates the current one

$newToken = $this->auth->refresh();

invalidate()

Invalidate the token (add it to the blacklist)

$this->auth->invalidate();

tokenById()

Get a token based on a given user's id.

$token = $this->auth->tokenById(1);

payload()

Get the raw JWT payload

$payload = $this->auth->payload();

// then you can access the claims directly e.g.
$payload->get('sub'); // = 1
$payload['jti']; // = 'sFF32fsDfs'
$payload('exp') // = 1665544846
$payload->toArray(); // = ['sub' => 1, 'exp' => 1665544846, 'jti' => 'sFF32fsDfs'] etc

validate()

Validate a user's credentials

if ($this->auth->validate($credentials)) {
    // credentials are valid
}

More advanced usage

Adding custom claims

$token = $this->auth->claims(['username' => 'phalconist'])->attempt($credentials);

Set the token explicitly

$user = $this->auth->setToken('eyJhb...')->user();

Check token

Checking the token for correctness

$this->auth->parseToken()->checkOrFail()

Will return true if everything is ok or Exceptions:

  • Sinbadxiii\PhalconAuthJWT\Exceptions\TokenExpiredException ('The token has expired')
  • Sinbadxiii\PhalconAuthJWT\Exceptions\TokenBlacklistedException ('The token has been blacklisted')
  • Sinbadxiii\PhalconAuthJWT\Exceptions\TokenInvalidException

License

The MIT License (MIT). Please see License File for more information.

phalcon-auth-jwt's People

Contributors

sinbadxiii avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.