Skip to content

Commit 7e44545

Browse files
committed
Added Refresh Token and Access Token in place of basic Token
1 parent 7f0d0e3 commit 7e44545

File tree

5 files changed

+115
-77
lines changed

5 files changed

+115
-77
lines changed

app/config/routes.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
/**
44
* Routes Definition
55
*
6-
* ? Allowed Headers:
7-
* ? - Allowed origins: *
6+
* ? Headers:
7+
* ? - Allowed origins: $_ENV['CLIENT_ADDRESS']
88
* ? - Allowed methods: GET, POST, PUT, DELETE, OPTIONS
99
* ? - Allowed headers: Content-Type, Authorization, X-Requested-With
1010
* ? - Allowed credentials: true

app/controllers/Api.php

Lines changed: 9 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -39,16 +39,13 @@ public function index()
3939

4040
if ($examples === false) {
4141
Router::abort(500, json_encode([
42-
'status' => 'error',
4342
'message' => 'Server error'
4443
]));
4544
}
4645

47-
Response::send([
48-
'status' => 'success',
49-
'data' => $examples,
50-
'count' => count($examples)
51-
]);
46+
Response::send(
47+
$examples
48+
);
5249
}
5350

5451
/**
@@ -59,10 +56,9 @@ public function index()
5956
*/
6057
public function show($data = [])
6158
{
62-
Response::send([
63-
'status' => 'success',
64-
'data' => $this->model->get($data['id'])
65-
]);
59+
Response::send(
60+
$this->model->get($data['id'])
61+
);
6662
}
6763

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

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

86-
$example = $this->model->get(
87-
$this->model->getLastInsertedId()
88-
);
89-
9081
Response::send([
91-
'status' => 'success',
92-
'data' => $example
82+
'message' => 'Created successfully'
9383
]);
9484
}
9585

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

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

114-
$example = $this->model->get($id);
115-
116103
Response::send([
117-
'status' => 'success',
118-
'data' => $example
104+
'message' => 'Updated successfully'
119105
]);
120106
}
121107

@@ -129,13 +115,12 @@ public function delete($data = [])
129115
{
130116
if (!$this->model->delete($data['id'])) {
131117
Router::abort(500, json_encode([
132-
'status' => 'error',
133118
'message' => 'Server error'
134119
]));
135120
}
136121

137122
Response::send([
138-
'status' => 'success'
123+
'message' => 'Deleted successfully'
139124
]);
140125
}
141126
}

app/controllers/Auth.php

Lines changed: 87 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use Core\{Controller, Router};
77
use Core\Helpers\Request;
88
use Core\Helpers\Response;
9+
use Exception;
910
use Firebase\JWT\{JWT, Key};
1011

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

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

48-
$example = $this->model('Example')->get(
49-
$this->model('Example')->getLastInsertedId()
50-
);
51-
5248
Response::send([
53-
'status' => 'success',
54-
'data' => $example
49+
'message' => 'Registered successfully',
5550
]);
5651
}
5752

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

68-
Response::send([
69-
'status' => 'success',
70-
'data' => $example
71-
]);
63+
Response::send(
64+
$example
65+
);
7266
}
7367

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

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

9285
unset($data['password']);
9386

9487
Response::send([
95-
'status' => 'success',
96-
'data' => $data
88+
'message' => 'Registered successfully',
9789
]);
9890
}
9991

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

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

117-
$secret_key = $_ENV['JWT_SECRET_KEY'];
118-
$issuer_claim = $_ENV['SERVER_ADDRESS']; // this can be the servername
119-
$audience_claim = $_ENV['CLIENT_ADDRESS'];
120-
$issuedat_claim = time(); // issued at
121-
// $notbefore_claim = $issuedat_claim + 10; //not before in seconds
122-
$expire_claim = $issuedat_claim + 600; // expire time in seconds (10 minutes)
123-
$payload = array(
124-
"iss" => $issuer_claim,
125-
"aud" => $audience_claim,
126-
"iat" => $issuedat_claim,
127-
// "nbf" => $notbefore_claim,
128-
"exp" => $expire_claim,
129-
"sub" => $example->username
130-
);
108+
// Create Refresh Token
109+
$refreshToken = $this->createToken($example->username, $_ENV['JWT_REFRESH_EXP_DELTA_SECONDS']);
131110

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

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

137124
Response::send(
138-
array(
139-
"message" => "Successful login.",
140-
"jwt" => $jwt
141-
)
125+
$example
142126
);
143127
}
144128

129+
/**
130+
* Refresh Access Token
131+
*
132+
* @param array $data
133+
* @return void
134+
*/
135+
public function refresh()
136+
{
137+
$refreshToken = Request::refreshToken();
138+
139+
// Check if refresh token is valid
140+
try {
141+
if (!$refreshToken) {
142+
throw new Exception('No refresh token found');
143+
}
144+
145+
$token = JWT::decode($refreshToken, new Key($_ENV['JWT_SECRET_KEY'], $_ENV['JWT_ALGORITHM']));
146+
147+
// Check if Example exists
148+
$example = (new Example())->getBy('username', $token->sub);
149+
if (!$example) {
150+
throw new Exception('Example not found');
151+
}
152+
153+
Response::send([
154+
'accessToken' => $this->createToken($example->username, $_ENV['JWT_ACCESS_EXP_DELTA_SECONDS'])
155+
]);
156+
} catch (Exception $e) {
157+
Router::abort(401, [
158+
'message' => 'Unauthorized: ' . $e->getMessage()
159+
]);
160+
}
161+
}
162+
145163
/**
146164
* Logout an User
147165
*
148166
* @return void
149167
*/
150168
public function logoutJWT()
151169
{
152-
setcookie(name: 'jwt', value: '', expires_or_options: time() - 3600, httponly: true);
170+
setcookie(name: 'auth', value: '', expires_or_options: time() - 1, httponly: true);
153171

154172
Response::send([
155-
'status' => 'Logged out successfully!'
173+
'message' => 'Logged out successfully!'
156174
]);
157175
}
158176

@@ -169,8 +187,37 @@ public static function userJWT()
169187
return null;
170188
}
171189

172-
$token = JWT::decode($jwt, new Key($_ENV['JWT_SECRET_KEY'], "HS256"));
190+
$token = JWT::decode($jwt, new Key($_ENV['JWT_SECRET_KEY'], $_ENV['JWT_ALGORITHM']));
191+
192+
$example = (new Example)->getBy('username', $token->sub);
193+
194+
unset($example->password,$example->id);
195+
196+
return$example;
197+
}
198+
199+
/**
200+
* Create token for user
201+
*
202+
* @param string $sub
203+
* @param int $exp
204+
* @return string
205+
*/
206+
public static function createToken($sub, $exp)
207+
{
208+
$secret_key = $_ENV['JWT_SECRET_KEY'];
209+
$issuer_claim = $_ENV['SERVER_ADDRESS']; // this can be the servername
210+
$audience_claim = $_ENV['CLIENT_ADDRESS'];
211+
$issuedat_claim = time(); // issued at
212+
$expire_claim = $issuedat_claim + $exp; // expire time in seconds (24 hours from now)
213+
$payload = array(
214+
"iss" => $issuer_claim,
215+
"aud" => $audience_claim,
216+
"iat" => $issuedat_claim,
217+
"exp" => $expire_claim,
218+
"sub" => $sub
219+
);
173220

174-
return (new Example)->getBy('username', $token->sub);
221+
return JWT::encode($payload, $secret_key, $_ENV['JWT_ALGORITHM']);
175222
}
176223
}

core/helpers/Request.php

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,8 @@ public static function header($header)
9191
return $_SERVER['HTTP_' . $header] ?? null;
9292
}
9393

94-
9594
/**
96-
* Get Authorization header value.
95+
* Get Authorization jwt access token
9796
*
9897
* @return string
9998
*/
@@ -102,13 +101,18 @@ public static function authorization()
102101
// Get authorization token from header
103102
$auth = isset($_SERVER['Authorization']) && preg_match('/Bearer\s(\S+)/', $_SERVER['Authorization'], $matches) ? $matches[1] : null;
104103

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

112106
return $auth ?? false;
113107
}
108+
109+
/**
110+
* Get Refresh Token from httponly Cookie
111+
*
112+
* @return string
113+
*/
114+
public static function refreshToken()
115+
{
116+
return isset($_COOKIE['auth']) ? $_COOKIE['auth'] : false;
117+
}
114118
}

core/helpers/Response.php

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,11 @@ class Response
99
*/
1010
public static function headers(
1111
$contentType = 'application/json',
12-
$allowOrigin = '*',
1312
$allowMethods = 'GET, POST, PUT, DELETE, OPTIONS',
1413
$allowHeaders = 'X-Requested-With, Content-Type, Authorization'
1514
) {
1615
header('Content-Type: ' . $contentType . '; charset=UTF-8');
17-
header('Access-Control-Allow-Origin: ' . $allowOrigin);
16+
header('Access-Control-Allow-Origin: ' . $_ENV['CLIENT_ADDRESS']);
1817
header('Access-Control-Allow-Methods: ' . $allowMethods);
1918
header('Access-Control-Allow-Headers: ' . $allowHeaders);
2019
header('Access-Control-Allow-Credentials: true');
@@ -29,7 +28,10 @@ public static function headers(
2928
*/
3029
public static function send($response)
3130
{
32-
exit(json_encode($response));
31+
if (is_array($response) || is_object($response)) {
32+
$response = json_encode($response);
33+
}
34+
exit($response);
3335
}
3436

3537
/**

0 commit comments

Comments
 (0)