Skip to content

Commit

Permalink
Added Refresh Token and Access Token in place of basic Token
Browse files Browse the repository at this point in the history
  • Loading branch information
aymenBenadra committed May 17, 2022
1 parent 7f0d0e3 commit 7e44545
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 77 deletions.
4 changes: 2 additions & 2 deletions app/config/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
/**
* Routes Definition
*
* ? Allowed Headers:
* ? - Allowed origins: *
* ? Headers:
* ? - Allowed origins: $_ENV['CLIENT_ADDRESS']
* ? - Allowed methods: GET, POST, PUT, DELETE, OPTIONS
* ? - Allowed headers: Content-Type, Authorization, X-Requested-With
* ? - Allowed credentials: true
Expand Down
33 changes: 9 additions & 24 deletions app/controllers/Api.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,13 @@ public function index()

if ($examples === false) {
Router::abort(500, json_encode([
'status' => 'error',
'message' => 'Server error'
]));
}

Response::send([
'status' => 'success',
'data' => $examples,
'count' => count($examples)
]);
Response::send(
$examples
);
}

/**
Expand All @@ -59,10 +56,9 @@ public function index()
*/
public function show($data = [])
{
Response::send([
'status' => 'success',
'data' => $this->model->get($data['id'])
]);
Response::send(
$this->model->get($data['id'])
);
}

/**
Expand All @@ -78,18 +74,12 @@ public function store($data = [])

if (!$this->model->add($data)) {
Router::abort(500, json_encode([
'status' => 'error',
'message' => 'Server error'
]));
}

$example = $this->model->get(
$this->model->getLastInsertedId()
);

Response::send([
'status' => 'success',
'data' => $example
'message' => 'Created successfully'
]);
}

Expand All @@ -106,16 +96,12 @@ public function update($data = [])

if (!$this->model->update($id, $data)) {
Router::abort(500, json_encode([
'status' => 'error',
'message' => 'Server error'
]));
}

$example = $this->model->get($id);

Response::send([
'status' => 'success',
'data' => $example
'message' => 'Updated successfully'
]);
}

Expand All @@ -129,13 +115,12 @@ public function delete($data = [])
{
if (!$this->model->delete($data['id'])) {
Router::abort(500, json_encode([
'status' => 'error',
'message' => 'Server error'
]));
}

Response::send([
'status' => 'success'
'message' => 'Deleted successfully'
]);
}
}
127 changes: 87 additions & 40 deletions app/controllers/Auth.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use Core\{Controller, Router};
use Core\Helpers\Request;
use Core\Helpers\Response;
use Exception;
use Firebase\JWT\{JWT, Key};

/**
Expand Down Expand Up @@ -40,18 +41,12 @@ public function registerHeader($data = [])

if (!$this->model('Example')->add($data)) {
Router::abort(500, json_encode([
'status' => 'error',
'message' => 'Server error'
]));
}

$example = $this->model('Example')->get(
$this->model('Example')->getLastInsertedId()
);

Response::send([
'status' => 'success',
'data' => $example
'message' => 'Registered successfully',
]);
}

Expand All @@ -65,10 +60,9 @@ public function login($data = [])
{
$example = $this->model('Example')->getBy('headerRef', $data['headerRef']);

Response::send([
'status' => 'success',
'data' => $example
]);
Response::send(
$example
);
}

/**
Expand All @@ -84,16 +78,14 @@ public function registerJWT($data = [])

if (!$this->model('Example')->add($data)) {
Router::abort(500, json_encode([
'status' => 'error',
'message' => 'Server error'
]));
}

unset($data['password']);

Response::send([
'status' => 'success',
'data' => $data
'message' => 'Registered successfully',
]);
}

Expand All @@ -109,50 +101,76 @@ public function loginJWT($data = [])

if (!password_verify($data['password'], $example->password)) {
Router::abort(401, json_encode([
'status' => 'error',
'message' => 'Invalid password'
]));
}

$secret_key = $_ENV['JWT_SECRET_KEY'];
$issuer_claim = $_ENV['SERVER_ADDRESS']; // this can be the servername
$audience_claim = $_ENV['CLIENT_ADDRESS'];
$issuedat_claim = time(); // issued at
// $notbefore_claim = $issuedat_claim + 10; //not before in seconds
$expire_claim = $issuedat_claim + 600; // expire time in seconds (10 minutes)
$payload = array(
"iss" => $issuer_claim,
"aud" => $audience_claim,
"iat" => $issuedat_claim,
// "nbf" => $notbefore_claim,
"exp" => $expire_claim,
"sub" => $example->username
);
// Create Refresh Token
$refreshToken = $this->createToken($example->username, $_ENV['JWT_REFRESH_EXP_DELTA_SECONDS']);

$jwt = JWT::encode($payload, $secret_key, "HS256");
setcookie(
name: 'auth',
value: $refreshToken,
expires_or_options: time() + $_ENV['JWT_REFRESH_EXP_DELTA_SECONDS'],
httponly: true
);
// Create Access Token
$accessToken = $this->createToken($example->username, $_ENV['JWT_ACCESS_EXP_DELTA_SECONDS']);

// Set expirable cookie for JWT
setcookie(name: 'jwt', value: $jwt, expires_or_options: $expire_claim, httponly: true);
unset($example->password, $example->id);
$example->avatar = file_get_contents(dirname(dirname(__DIR__)) . "/public/identicons/" . $example->avatar);
$example->accessToken = $accessToken;

Response::send(
array(
"message" => "Successful login.",
"jwt" => $jwt
)
$example
);
}

/**
* Refresh Access Token
*
* @param array $data
* @return void
*/
public function refresh()
{
$refreshToken = Request::refreshToken();

// Check if refresh token is valid
try {
if (!$refreshToken) {
throw new Exception('No refresh token found');
}

$token = JWT::decode($refreshToken, new Key($_ENV['JWT_SECRET_KEY'], $_ENV['JWT_ALGORITHM']));

// Check if Example exists
$example = (new Example())->getBy('username', $token->sub);
if (!$example) {
throw new Exception('Example not found');
}

Response::send([
'accessToken' => $this->createToken($example->username, $_ENV['JWT_ACCESS_EXP_DELTA_SECONDS'])
]);
} catch (Exception $e) {
Router::abort(401, [
'message' => 'Unauthorized: ' . $e->getMessage()
]);
}
}

/**
* Logout an User
*
* @return void
*/
public function logoutJWT()
{
setcookie(name: 'jwt', value: '', expires_or_options: time() - 3600, httponly: true);
setcookie(name: 'auth', value: '', expires_or_options: time() - 1, httponly: true);

Response::send([
'status' => 'Logged out successfully!'
'message' => 'Logged out successfully!'
]);
}

Expand All @@ -169,8 +187,37 @@ public static function userJWT()
return null;
}

$token = JWT::decode($jwt, new Key($_ENV['JWT_SECRET_KEY'], "HS256"));
$token = JWT::decode($jwt, new Key($_ENV['JWT_SECRET_KEY'], $_ENV['JWT_ALGORITHM']));

$example = (new Example)->getBy('username', $token->sub);

unset($example->password,$example->id);

return$example;
}

/**
* Create token for user
*
* @param string $sub
* @param int $exp
* @return string
*/
public static function createToken($sub, $exp)
{
$secret_key = $_ENV['JWT_SECRET_KEY'];
$issuer_claim = $_ENV['SERVER_ADDRESS']; // this can be the servername
$audience_claim = $_ENV['CLIENT_ADDRESS'];
$issuedat_claim = time(); // issued at
$expire_claim = $issuedat_claim + $exp; // expire time in seconds (24 hours from now)
$payload = array(
"iss" => $issuer_claim,
"aud" => $audience_claim,
"iat" => $issuedat_claim,
"exp" => $expire_claim,
"sub" => $sub
);

return (new Example)->getBy('username', $token->sub);
return JWT::encode($payload, $secret_key, $_ENV['JWT_ALGORITHM']);
}
}
20 changes: 12 additions & 8 deletions core/helpers/Request.php
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,8 @@ public static function header($header)
return $_SERVER['HTTP_' . $header] ?? null;
}


/**
* Get Authorization header value.
* Get Authorization jwt access token
*
* @return string
*/
Expand All @@ -102,13 +101,18 @@ public static function authorization()
// Get authorization token from header
$auth = isset($_SERVER['Authorization']) && preg_match('/Bearer\s(\S+)/', $_SERVER['Authorization'], $matches) ? $matches[1] : null;

$auth ?? $auth = isset($_SERVER['HTTP_AUTHORIZATION']) && preg_match('/Bearer\s(\S+)/', $_SERVER['HTTP_AUTHORIZATION'], $matches) ? $matches[1] : null;

// If no authorization token, get it from cookie
if (!$auth) {
$auth = isset($_COOKIE['jwt']) ? $_COOKIE['jwt'] : null;
}
$auth ??= isset($_SERVER['HTTP_AUTHORIZATION']) && preg_match('/Bearer\s(\S+)/', $_SERVER['HTTP_AUTHORIZATION'], $matches) ? $matches[1] : null;

return $auth ?? false;
}

/**
* Get Refresh Token from httponly Cookie
*
* @return string
*/
public static function refreshToken()
{
return isset($_COOKIE['auth']) ? $_COOKIE['auth'] : false;
}
}
8 changes: 5 additions & 3 deletions core/helpers/Response.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,11 @@ class Response
*/
public static function headers(
$contentType = 'application/json',
$allowOrigin = '*',
$allowMethods = 'GET, POST, PUT, DELETE, OPTIONS',
$allowHeaders = 'X-Requested-With, Content-Type, Authorization'
) {
header('Content-Type: ' . $contentType . '; charset=UTF-8');
header('Access-Control-Allow-Origin: ' . $allowOrigin);
header('Access-Control-Allow-Origin: ' . $_ENV['CLIENT_ADDRESS']);
header('Access-Control-Allow-Methods: ' . $allowMethods);
header('Access-Control-Allow-Headers: ' . $allowHeaders);
header('Access-Control-Allow-Credentials: true');
Expand All @@ -29,7 +28,10 @@ public static function headers(
*/
public static function send($response)
{
exit(json_encode($response));
if (is_array($response) || is_object($response)) {
$response = json_encode($response);
}
exit($response);
}

/**
Expand Down

0 comments on commit 7e44545

Please sign in to comment.