lonnieezell / myth-auth

One-stop Auth package for CodeIgniter 4
MIT License
625 stars 207 forks source link

JWT Authentication Support #286

Closed nicojmb closed 2 years ago

nicojmb commented 3 years ago

Hi, i see in Roadmap that you consider the support of "JWT Authentication".

I would love this feature, if any has already do it, please share to MyAuth!!!!

Regards!!

lonnieezell commented 3 years ago

Has not happened yet. Development slowed for a while so we could get CI 4 out the door, and since then my day job has kep me on OT for the last 6 months. The project is almost wrapped, so I hope to be able to get back to this soon.

rafinhaa commented 2 years ago

Any news?

MGatner commented 2 years ago

@rafinhaa I do not expect that any of the maintainers are going to implement this. If someone from the community wants to create a PR we can review it but we are all very busy on other projects and this isn't a priority.

sandrocantagallo commented 2 years ago

Controller Apiuser.php

<?php

namespace App\Controllers;

use App\Controllers\BaseController;
use CodeIgniter\RESTful\ResourceController;
use Exception;
use CodeIgniter\API\ResponseTrait;
use \Firebase\JWT\JWT;
use Myth\Auth\Models\LoginModel;
use Myth\Auth\Models\UserModel;
use Firebase\JWT\Key;

class Apiuser extends BaseController
{
    use ResponseTrait;

    public function login()
    {
        $rules = [
            "email" => "required|valid_email|min_length[6]",
            "password" => "required",
        ];

        $messages = [
            "email" => [
                "required" => "Email required",
                "valid_email" => "Email address is not in format"
            ],
            "password" => [
                "required" => "password is required"
            ],
        ];

        if (!$this->validate($rules, $messages)) {

            $response = [
                'status' => 500,
                'error' => true,
                'message' => $this->validator->getErrors(),
                'data' => []
            ];

            return $this->respondCreated($response);

        } else {
            $userModel = new UserModel();

            $userdata = $userModel->where("email", $this->request->getVar("email"))->first();

            if (!empty($userdata)) {

                $this->auth = service('authentication');

                $type = "email";

             if ( $this->auth->attempt([$type => $userdata->email, 'password' => $this->request->getVar("password")], false))
             {

                    $key = $this->getKey();

                    $iat = time(); // current timestamp value
                    $nbf = $iat + 10;
                    $exp = $iat + 3600;

                    $payload = array(
                        "iss" => "The_claim",
                        "aud" => "The_Aud",
                        "iat" => $iat, // issued at
                        "nbf" => $nbf, //not before in seconds
                        "exp" => $exp, // expire time in seconds
                        "data" => $userdata,
                    );

                    $token = JWT::encode($payload, $key, 'HS256');

                    $response = [
                        'status' => 200,
                        'error' => false,
                        'messages' => 'User logged In successfully',
                        'data' => [
                            'token' => $token
                        ]
                    ];
                    return $this->respondCreated($response);
                } else {

                    $response = [
                        'status' => 500,
                        'error' => true,
                        'messages' => 'Incorrect details',
                        'data' => []
                    ];
                    return $this->respondCreated($response);
                }
            } else {
                $response = [
                    'status' => 500,
                    'error' => true,
                    'messages' => 'User not found',
                    'data' => []
                ];
                return $this->respondCreated($response);
            }
        }
    }

    public function details()
    {
        $key = $this->getKey();
        $authHeader = $this->request->getHeader("Authorization");
        $authHeader = $authHeader->getValue();
        $token = $authHeader;

        try {

            $decoded = JWT::decode($token, new Key($key, "HS256"));

            if ($decoded) {

                $response = [
                    'status' => 200,
                    'error' => false,
                    'messages' => 'User details',
                    'data' => [
                        'profile' => $decoded
                    ]
                ];
                return $this->respondCreated($response);
            }
        } catch (Exception $ex) {
            $response = [
                'status' => 401,
                'error' => true,
                'messages' => 'Access denied',
                'data' => []
            ];
            return $this->respondCreated($response);
        }
    }

    private function getKey()
    {
        return "my_application_secret";
    }
}

Insert this route: app/Config/Routes.php

$routes->group("api", function ($routes) {
    $routes->post("register", "Apiuser::register");
    $routes->post("login", "Apiuser::login");
    $routes->get("profile", "Apiuser::details");
});

Enjoy.

lbshopping commented 2 years ago

Controller Apiuser.php

<?php

namespace App\Controllers;

use App\Controllers\BaseController;
use CodeIgniter\RESTful\ResourceController;
use Exception;
use CodeIgniter\API\ResponseTrait;
use \Firebase\JWT\JWT;
use Myth\Auth\Models\LoginModel;
use Myth\Auth\Models\UserModel;
use Firebase\JWT\Key;

class Apiuser extends BaseController
{
  use ResponseTrait;

  public function login()
  {
      $rules = [
            "email" => "required|valid_email|min_length[6]",
            "password" => "required",
        ];

        $messages = [
            "email" => [
                "required" => "Email required",
                "valid_email" => "Email address is not in format"
            ],
            "password" => [
                "required" => "password is required"
            ],
        ];

        if (!$this->validate($rules, $messages)) {

            $response = [
                'status' => 500,
                'error' => true,
                'message' => $this->validator->getErrors(),
                'data' => []
            ];

            return $this->respondCreated($response);

        } else {
            $userModel = new UserModel();

            $userdata = $userModel->where("email", $this->request->getVar("email"))->first();

            if (!empty($userdata)) {

              $this->auth = service('authentication');

              $type = "email";

           if ( $this->auth->attempt([$type => $userdata->email, 'password' => $this->request->getVar("password")], false))
           {

                    $key = $this->getKey();

                    $iat = time(); // current timestamp value
                    $nbf = $iat + 10;
                    $exp = $iat + 3600;

                    $payload = array(
                        "iss" => "The_claim",
                        "aud" => "The_Aud",
                        "iat" => $iat, // issued at
                        "nbf" => $nbf, //not before in seconds
                        "exp" => $exp, // expire time in seconds
                        "data" => $userdata,
                    );

                    $token = JWT::encode($payload, $key, 'HS256');

                    $response = [
                        'status' => 200,
                        'error' => false,
                        'messages' => 'User logged In successfully',
                        'data' => [
                            'token' => $token
                        ]
                    ];
                    return $this->respondCreated($response);
                } else {

                    $response = [
                        'status' => 500,
                        'error' => true,
                        'messages' => 'Incorrect details',
                        'data' => []
                    ];
                    return $this->respondCreated($response);
                }
            } else {
                $response = [
                    'status' => 500,
                    'error' => true,
                    'messages' => 'User not found',
                    'data' => []
                ];
                return $this->respondCreated($response);
            }
        }
  }

  public function details()
    {
        $key = $this->getKey();
        $authHeader = $this->request->getHeader("Authorization");
        $authHeader = $authHeader->getValue();
        $token = $authHeader;

        try {

            $decoded = JWT::decode($token, new Key($key, "HS256"));

            if ($decoded) {

                $response = [
                    'status' => 200,
                    'error' => false,
                    'messages' => 'User details',
                    'data' => [
                        'profile' => $decoded
                    ]
                ];
                return $this->respondCreated($response);
            }
        } catch (Exception $ex) {
            $response = [
                'status' => 401,
                'error' => true,
                'messages' => 'Access denied',
                'data' => []
            ];
            return $this->respondCreated($response);
        }
    }

  private function getKey()
    {
        return "my_application_secret";
    }
}

Insert this route: app/Config/Routes.php

$routes->group("api", function ($routes) {
    $routes->post("register", "Apiuser::register");
    $routes->post("login", "Apiuser::login");
    $routes->get("profile", "Apiuser::details");
});

Enjoy.

Looks great! Thanks! The token expires after 1 hour, how can we renew the token easily without logging the user out?

MGatner commented 2 years ago

There's some good work in here but if this aims to be part of the library it will need to be an actual Pull Request with tests and docs.