├── .env.example ├── .gitignore ├── README.md ├── composer.json ├── composer.lock ├── cors.php ├── games.php ├── login.php ├── me.php └── refresh-token.php /.env.example: -------------------------------------------------------------------------------- 1 | FRONTEND_URL= 2 | ACCESS_TOKEN_SECRET= 3 | REFRESH_TOKEN_SECRET= -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | vendor 2 | .env -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # jwt-php-native 2 | Implementasi JWT dengan PHP native 3 | 4 | ## Requirements 5 | 1. Composer 6 | 2. PHP 7 | 3. Apache 8 | 9 | ## Instalasi 10 | 1. Clone proyek ini 11 | ```bash 12 | git clone https://github.com/itsfaqih/jwt-php-native.git 13 | cd jwt-php-native 14 | ``` 15 | 2. Install dependency 16 | ```bash 17 | composer install 18 | ``` 19 | 3. Copy .env.example dengan nama .env, dan sesuaikan setting 20 | 4. Jalankan web server 21 | ```bash 22 | php -S localhost:8000 23 | ``` 24 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "itsfaqih/jwt", 3 | "authors": [ 4 | { 5 | "name": "Faqih Muntashir", 6 | "email": "itsfaqih@gmail.com" 7 | } 8 | ], 9 | "require": { 10 | "vlucas/phpdotenv": "^5.2", 11 | "firebase/php-jwt": "^5.2" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", 5 | "This file is @generated automatically" 6 | ], 7 | "content-hash": "f2cac2eb552d8171f4ea968d32eedad7", 8 | "packages": [ 9 | { 10 | "name": "firebase/php-jwt", 11 | "version": "v5.2.0", 12 | "source": { 13 | "type": "git", 14 | "url": "https://github.com/firebase/php-jwt.git", 15 | "reference": "feb0e820b8436873675fd3aca04f3728eb2185cb" 16 | }, 17 | "dist": { 18 | "type": "zip", 19 | "url": "https://api.github.com/repos/firebase/php-jwt/zipball/feb0e820b8436873675fd3aca04f3728eb2185cb", 20 | "reference": "feb0e820b8436873675fd3aca04f3728eb2185cb", 21 | "shasum": "" 22 | }, 23 | "require": { 24 | "php": ">=5.3.0" 25 | }, 26 | "require-dev": { 27 | "phpunit/phpunit": ">=4.8 <=9" 28 | }, 29 | "type": "library", 30 | "autoload": { 31 | "psr-4": { 32 | "Firebase\\JWT\\": "src" 33 | } 34 | }, 35 | "notification-url": "https://packagist.org/downloads/", 36 | "license": [ 37 | "BSD-3-Clause" 38 | ], 39 | "authors": [ 40 | { 41 | "name": "Neuman Vong", 42 | "email": "neuman+pear@twilio.com", 43 | "role": "Developer" 44 | }, 45 | { 46 | "name": "Anant Narayanan", 47 | "email": "anant@php.net", 48 | "role": "Developer" 49 | } 50 | ], 51 | "description": "A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.", 52 | "homepage": "https://github.com/firebase/php-jwt", 53 | "keywords": [ 54 | "jwt", 55 | "php" 56 | ], 57 | "support": { 58 | "issues": "https://github.com/firebase/php-jwt/issues", 59 | "source": "https://github.com/firebase/php-jwt/tree/master" 60 | }, 61 | "time": "2020-03-25T18:49:23+00:00" 62 | }, 63 | { 64 | "name": "graham-campbell/result-type", 65 | "version": "v1.0.1", 66 | "source": { 67 | "type": "git", 68 | "url": "https://github.com/GrahamCampbell/Result-Type.git", 69 | "reference": "7e279d2cd5d7fbb156ce46daada972355cea27bb" 70 | }, 71 | "dist": { 72 | "type": "zip", 73 | "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/7e279d2cd5d7fbb156ce46daada972355cea27bb", 74 | "reference": "7e279d2cd5d7fbb156ce46daada972355cea27bb", 75 | "shasum": "" 76 | }, 77 | "require": { 78 | "php": "^7.0|^8.0", 79 | "phpoption/phpoption": "^1.7.3" 80 | }, 81 | "require-dev": { 82 | "phpunit/phpunit": "^6.5|^7.5|^8.5|^9.0" 83 | }, 84 | "type": "library", 85 | "extra": { 86 | "branch-alias": { 87 | "dev-master": "1.0-dev" 88 | } 89 | }, 90 | "autoload": { 91 | "psr-4": { 92 | "GrahamCampbell\\ResultType\\": "src/" 93 | } 94 | }, 95 | "notification-url": "https://packagist.org/downloads/", 96 | "license": [ 97 | "MIT" 98 | ], 99 | "authors": [ 100 | { 101 | "name": "Graham Campbell", 102 | "email": "graham@alt-three.com" 103 | } 104 | ], 105 | "description": "An Implementation Of The Result Type", 106 | "keywords": [ 107 | "Graham Campbell", 108 | "GrahamCampbell", 109 | "Result Type", 110 | "Result-Type", 111 | "result" 112 | ], 113 | "support": { 114 | "issues": "https://github.com/GrahamCampbell/Result-Type/issues", 115 | "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.0.1" 116 | }, 117 | "funding": [ 118 | { 119 | "url": "https://github.com/GrahamCampbell", 120 | "type": "github" 121 | }, 122 | { 123 | "url": "https://tidelift.com/funding/github/packagist/graham-campbell/result-type", 124 | "type": "tidelift" 125 | } 126 | ], 127 | "time": "2020-04-13T13:17:36+00:00" 128 | }, 129 | { 130 | "name": "phpoption/phpoption", 131 | "version": "1.7.5", 132 | "source": { 133 | "type": "git", 134 | "url": "https://github.com/schmittjoh/php-option.git", 135 | "reference": "994ecccd8f3283ecf5ac33254543eb0ac946d525" 136 | }, 137 | "dist": { 138 | "type": "zip", 139 | "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/994ecccd8f3283ecf5ac33254543eb0ac946d525", 140 | "reference": "994ecccd8f3283ecf5ac33254543eb0ac946d525", 141 | "shasum": "" 142 | }, 143 | "require": { 144 | "php": "^5.5.9 || ^7.0 || ^8.0" 145 | }, 146 | "require-dev": { 147 | "bamarni/composer-bin-plugin": "^1.4.1", 148 | "phpunit/phpunit": "^4.8.35 || ^5.7.27 || ^6.5.6 || ^7.0 || ^8.0 || ^9.0" 149 | }, 150 | "type": "library", 151 | "extra": { 152 | "branch-alias": { 153 | "dev-master": "1.7-dev" 154 | } 155 | }, 156 | "autoload": { 157 | "psr-4": { 158 | "PhpOption\\": "src/PhpOption/" 159 | } 160 | }, 161 | "notification-url": "https://packagist.org/downloads/", 162 | "license": [ 163 | "Apache-2.0" 164 | ], 165 | "authors": [ 166 | { 167 | "name": "Johannes M. Schmitt", 168 | "email": "schmittjoh@gmail.com" 169 | }, 170 | { 171 | "name": "Graham Campbell", 172 | "email": "graham@alt-three.com" 173 | } 174 | ], 175 | "description": "Option Type for PHP", 176 | "keywords": [ 177 | "language", 178 | "option", 179 | "php", 180 | "type" 181 | ], 182 | "support": { 183 | "issues": "https://github.com/schmittjoh/php-option/issues", 184 | "source": "https://github.com/schmittjoh/php-option/tree/1.7.5" 185 | }, 186 | "funding": [ 187 | { 188 | "url": "https://github.com/GrahamCampbell", 189 | "type": "github" 190 | }, 191 | { 192 | "url": "https://tidelift.com/funding/github/packagist/phpoption/phpoption", 193 | "type": "tidelift" 194 | } 195 | ], 196 | "time": "2020-07-20T17:29:33+00:00" 197 | }, 198 | { 199 | "name": "symfony/polyfill-ctype", 200 | "version": "v1.20.0", 201 | "source": { 202 | "type": "git", 203 | "url": "https://github.com/symfony/polyfill-ctype.git", 204 | "reference": "f4ba089a5b6366e453971d3aad5fe8e897b37f41" 205 | }, 206 | "dist": { 207 | "type": "zip", 208 | "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/f4ba089a5b6366e453971d3aad5fe8e897b37f41", 209 | "reference": "f4ba089a5b6366e453971d3aad5fe8e897b37f41", 210 | "shasum": "" 211 | }, 212 | "require": { 213 | "php": ">=7.1" 214 | }, 215 | "suggest": { 216 | "ext-ctype": "For best performance" 217 | }, 218 | "type": "library", 219 | "extra": { 220 | "branch-alias": { 221 | "dev-main": "1.20-dev" 222 | }, 223 | "thanks": { 224 | "name": "symfony/polyfill", 225 | "url": "https://github.com/symfony/polyfill" 226 | } 227 | }, 228 | "autoload": { 229 | "psr-4": { 230 | "Symfony\\Polyfill\\Ctype\\": "" 231 | }, 232 | "files": [ 233 | "bootstrap.php" 234 | ] 235 | }, 236 | "notification-url": "https://packagist.org/downloads/", 237 | "license": [ 238 | "MIT" 239 | ], 240 | "authors": [ 241 | { 242 | "name": "Gert de Pagter", 243 | "email": "BackEndTea@gmail.com" 244 | }, 245 | { 246 | "name": "Symfony Community", 247 | "homepage": "https://symfony.com/contributors" 248 | } 249 | ], 250 | "description": "Symfony polyfill for ctype functions", 251 | "homepage": "https://symfony.com", 252 | "keywords": [ 253 | "compatibility", 254 | "ctype", 255 | "polyfill", 256 | "portable" 257 | ], 258 | "support": { 259 | "source": "https://github.com/symfony/polyfill-ctype/tree/v1.20.0" 260 | }, 261 | "funding": [ 262 | { 263 | "url": "https://symfony.com/sponsor", 264 | "type": "custom" 265 | }, 266 | { 267 | "url": "https://github.com/fabpot", 268 | "type": "github" 269 | }, 270 | { 271 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 272 | "type": "tidelift" 273 | } 274 | ], 275 | "time": "2020-10-23T14:02:19+00:00" 276 | }, 277 | { 278 | "name": "symfony/polyfill-mbstring", 279 | "version": "v1.20.0", 280 | "source": { 281 | "type": "git", 282 | "url": "https://github.com/symfony/polyfill-mbstring.git", 283 | "reference": "39d483bdf39be819deabf04ec872eb0b2410b531" 284 | }, 285 | "dist": { 286 | "type": "zip", 287 | "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/39d483bdf39be819deabf04ec872eb0b2410b531", 288 | "reference": "39d483bdf39be819deabf04ec872eb0b2410b531", 289 | "shasum": "" 290 | }, 291 | "require": { 292 | "php": ">=7.1" 293 | }, 294 | "suggest": { 295 | "ext-mbstring": "For best performance" 296 | }, 297 | "type": "library", 298 | "extra": { 299 | "branch-alias": { 300 | "dev-main": "1.20-dev" 301 | }, 302 | "thanks": { 303 | "name": "symfony/polyfill", 304 | "url": "https://github.com/symfony/polyfill" 305 | } 306 | }, 307 | "autoload": { 308 | "psr-4": { 309 | "Symfony\\Polyfill\\Mbstring\\": "" 310 | }, 311 | "files": [ 312 | "bootstrap.php" 313 | ] 314 | }, 315 | "notification-url": "https://packagist.org/downloads/", 316 | "license": [ 317 | "MIT" 318 | ], 319 | "authors": [ 320 | { 321 | "name": "Nicolas Grekas", 322 | "email": "p@tchwork.com" 323 | }, 324 | { 325 | "name": "Symfony Community", 326 | "homepage": "https://symfony.com/contributors" 327 | } 328 | ], 329 | "description": "Symfony polyfill for the Mbstring extension", 330 | "homepage": "https://symfony.com", 331 | "keywords": [ 332 | "compatibility", 333 | "mbstring", 334 | "polyfill", 335 | "portable", 336 | "shim" 337 | ], 338 | "support": { 339 | "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.20.0" 340 | }, 341 | "funding": [ 342 | { 343 | "url": "https://symfony.com/sponsor", 344 | "type": "custom" 345 | }, 346 | { 347 | "url": "https://github.com/fabpot", 348 | "type": "github" 349 | }, 350 | { 351 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 352 | "type": "tidelift" 353 | } 354 | ], 355 | "time": "2020-10-23T14:02:19+00:00" 356 | }, 357 | { 358 | "name": "symfony/polyfill-php80", 359 | "version": "v1.20.0", 360 | "source": { 361 | "type": "git", 362 | "url": "https://github.com/symfony/polyfill-php80.git", 363 | "reference": "e70aa8b064c5b72d3df2abd5ab1e90464ad009de" 364 | }, 365 | "dist": { 366 | "type": "zip", 367 | "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/e70aa8b064c5b72d3df2abd5ab1e90464ad009de", 368 | "reference": "e70aa8b064c5b72d3df2abd5ab1e90464ad009de", 369 | "shasum": "" 370 | }, 371 | "require": { 372 | "php": ">=7.1" 373 | }, 374 | "type": "library", 375 | "extra": { 376 | "branch-alias": { 377 | "dev-main": "1.20-dev" 378 | }, 379 | "thanks": { 380 | "name": "symfony/polyfill", 381 | "url": "https://github.com/symfony/polyfill" 382 | } 383 | }, 384 | "autoload": { 385 | "psr-4": { 386 | "Symfony\\Polyfill\\Php80\\": "" 387 | }, 388 | "files": [ 389 | "bootstrap.php" 390 | ], 391 | "classmap": [ 392 | "Resources/stubs" 393 | ] 394 | }, 395 | "notification-url": "https://packagist.org/downloads/", 396 | "license": [ 397 | "MIT" 398 | ], 399 | "authors": [ 400 | { 401 | "name": "Ion Bazan", 402 | "email": "ion.bazan@gmail.com" 403 | }, 404 | { 405 | "name": "Nicolas Grekas", 406 | "email": "p@tchwork.com" 407 | }, 408 | { 409 | "name": "Symfony Community", 410 | "homepage": "https://symfony.com/contributors" 411 | } 412 | ], 413 | "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", 414 | "homepage": "https://symfony.com", 415 | "keywords": [ 416 | "compatibility", 417 | "polyfill", 418 | "portable", 419 | "shim" 420 | ], 421 | "support": { 422 | "source": "https://github.com/symfony/polyfill-php80/tree/v1.20.0" 423 | }, 424 | "funding": [ 425 | { 426 | "url": "https://symfony.com/sponsor", 427 | "type": "custom" 428 | }, 429 | { 430 | "url": "https://github.com/fabpot", 431 | "type": "github" 432 | }, 433 | { 434 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 435 | "type": "tidelift" 436 | } 437 | ], 438 | "time": "2020-10-23T14:02:19+00:00" 439 | }, 440 | { 441 | "name": "vlucas/phpdotenv", 442 | "version": "v5.2.0", 443 | "source": { 444 | "type": "git", 445 | "url": "https://github.com/vlucas/phpdotenv.git", 446 | "reference": "fba64139db67123c7a57072e5f8d3db10d160b66" 447 | }, 448 | "dist": { 449 | "type": "zip", 450 | "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/fba64139db67123c7a57072e5f8d3db10d160b66", 451 | "reference": "fba64139db67123c7a57072e5f8d3db10d160b66", 452 | "shasum": "" 453 | }, 454 | "require": { 455 | "ext-pcre": "*", 456 | "graham-campbell/result-type": "^1.0.1", 457 | "php": "^7.1.3 || ^8.0", 458 | "phpoption/phpoption": "^1.7.4", 459 | "symfony/polyfill-ctype": "^1.17", 460 | "symfony/polyfill-mbstring": "^1.17", 461 | "symfony/polyfill-php80": "^1.17" 462 | }, 463 | "require-dev": { 464 | "bamarni/composer-bin-plugin": "^1.4.1", 465 | "ext-filter": "*", 466 | "phpunit/phpunit": "^7.5.20 || ^8.5.2 || ^9.0" 467 | }, 468 | "suggest": { 469 | "ext-filter": "Required to use the boolean validator." 470 | }, 471 | "type": "library", 472 | "extra": { 473 | "branch-alias": { 474 | "dev-master": "5.2-dev" 475 | } 476 | }, 477 | "autoload": { 478 | "psr-4": { 479 | "Dotenv\\": "src/" 480 | } 481 | }, 482 | "notification-url": "https://packagist.org/downloads/", 483 | "license": [ 484 | "BSD-3-Clause" 485 | ], 486 | "authors": [ 487 | { 488 | "name": "Graham Campbell", 489 | "email": "graham@alt-three.com", 490 | "homepage": "https://gjcampbell.co.uk/" 491 | }, 492 | { 493 | "name": "Vance Lucas", 494 | "email": "vance@vancelucas.com", 495 | "homepage": "https://vancelucas.com/" 496 | } 497 | ], 498 | "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.", 499 | "keywords": [ 500 | "dotenv", 501 | "env", 502 | "environment" 503 | ], 504 | "support": { 505 | "issues": "https://github.com/vlucas/phpdotenv/issues", 506 | "source": "https://github.com/vlucas/phpdotenv/tree/v5.2.0" 507 | }, 508 | "funding": [ 509 | { 510 | "url": "https://github.com/GrahamCampbell", 511 | "type": "github" 512 | }, 513 | { 514 | "url": "https://tidelift.com/funding/github/packagist/vlucas/phpdotenv", 515 | "type": "tidelift" 516 | } 517 | ], 518 | "time": "2020-09-14T15:57:31+00:00" 519 | } 520 | ], 521 | "packages-dev": [], 522 | "aliases": [], 523 | "minimum-stability": "stable", 524 | "stability-flags": [], 525 | "prefer-stable": false, 526 | "prefer-lowest": false, 527 | "platform": [], 528 | "platform-dev": [], 529 | "plugin-api-version": "2.0.0" 530 | } 531 | -------------------------------------------------------------------------------- /cors.php: -------------------------------------------------------------------------------- 1 | load(); 8 | 9 | // Mengatasi CORS 10 | header('Access-Control-Allow-Origin: '.$_ENV['FRONTEND_URL']); 11 | header('Access-Control-Allow-Credentials: true'); 12 | header('Access-Control-Allow-Methods: HEAD, DELETE, POST, PUT, GET, OPTIONS'); 13 | header('Access-Control-Allow-Headers: Content-Type, Authorization'); 14 | header('Access-Control-Expose-Headers: Authorization'); 15 | 16 | if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { 17 | http_response_code(200); 18 | exit(); 19 | } -------------------------------------------------------------------------------- /games.php: -------------------------------------------------------------------------------- 1 | load(); 11 | 12 | // Atur jenis response 13 | header('Content-Type: application/json'); 14 | 15 | // Cek method request 16 | if ($_SERVER['REQUEST_METHOD'] !== 'GET') { 17 | http_response_code(405); 18 | exit(); 19 | } 20 | 21 | $headers = getallheaders(); 22 | 23 | // Periksa apakah header authorization-nya ada 24 | if (!isset($headers['Authorization'])) { 25 | http_response_code(401); 26 | exit(); 27 | } 28 | 29 | // Mengambil token 30 | list(, $token) = explode(' ', $headers['Authorization']); 31 | 32 | try { 33 | // Men-decode token. Dalam library ini juga sudah sekaligus memverfikasinya 34 | JWT::decode($token, $_ENV['ACCESS_TOKEN_SECRET'], ['HS256']); 35 | 36 | $games = [ 37 | [ 38 | 'title' => 'Dota 2', 39 | 'genre' => 'Strategy' 40 | ], 41 | [ 42 | 'title' => 'Ragnarok', 43 | 'genre' => 'Role Playing Game' 44 | ] 45 | ]; 46 | 47 | 48 | echo json_encode($games); 49 | } catch (Exception $e) { 50 | // Bagian ini akan jalan jika terdapat error saat JWT diverifikasi atau di-decode 51 | http_response_code(401); 52 | exit(); 53 | } 54 | -------------------------------------------------------------------------------- /login.php: -------------------------------------------------------------------------------- 1 | load(); 12 | 13 | // Atur jenis response 14 | header('Content-Type: application/json'); 15 | 16 | // Cek method request 17 | if ($_SERVER['REQUEST_METHOD'] !== 'POST') { 18 | http_response_code(405); 19 | exit(); 20 | } 21 | 22 | // Ambil data json yang dikirim user 23 | $json = file_get_contents('php://input'); 24 | $input = json_decode($json); 25 | 26 | // Jika tidak ada data email atau password 27 | if (!isset($input->email) || !isset($input->password)) { 28 | http_response_code(400); 29 | exit(); 30 | } 31 | 32 | $user = [ 33 | 'email' => 'johndoe@example.com', 34 | 'password' => 'qwerty123' 35 | ]; 36 | 37 | // Atur jenis response 38 | header('Content-Type: application/json'); 39 | 40 | // Jika email atau password tidak sesuai 41 | if ($input->email !== $user['email'] || $input->password !== $user['password']) { 42 | echo json_encode([ 43 | 'success' => false, 44 | 'data' => null, 45 | 'message' => 'Email atau password tidak sesuai' 46 | ]); 47 | exit(); 48 | } 49 | 50 | // Menghitung waktu kadaluarsa token. Dalam kasus ini akan terjadi setelah 15 menit 51 | $expired_time = time() + (15 * 60); 52 | 53 | // Buat payload dan access token 54 | $payload = [ 55 | 'email' => $input->email, 56 | // Di library ini wajib menambah key exp untuk mengatur masa berlaku token 57 | 'exp' => $expired_time 58 | ]; 59 | 60 | // Men-generate access token 61 | $access_token = JWT::encode($payload, $_ENV['ACCESS_TOKEN_SECRET']); 62 | 63 | // Kirim kembali ke user 64 | echo json_encode([ 65 | 'success' => true, 66 | 'data' => [ 67 | 'accessToken' => $access_token, 68 | 'expiry' => date(DATE_ISO8601, $expired_time) 69 | ], 70 | 'message' => 'Login berhasil!' 71 | ]); 72 | 73 | // Ubah waktu kadaluarsa lebih lama, dalam kasus ini 1 jam 74 | $payload['exp'] = time() + (60 * 60); 75 | $refresh_token = JWT::encode($payload, $_ENV['REFRESH_TOKEN_SECRET']); 76 | 77 | // Simpan refresh token di http-only cookie 78 | setcookie('refreshToken', $refresh_token, $payload['exp'], '', '', false, true); 79 | -------------------------------------------------------------------------------- /me.php: -------------------------------------------------------------------------------- 1 | load(); 12 | 13 | // Atur jenis response 14 | header('Content-Type: application/json'); 15 | 16 | // Cek method request 17 | if ($_SERVER['REQUEST_METHOD'] !== 'GET') { 18 | http_response_code(405); 19 | exit(); 20 | } 21 | 22 | $headers = getallheaders(); 23 | 24 | // Periksa apakah header authorization-nya ada 25 | if (!isset($headers['Authorization'])) { 26 | http_response_code(401); 27 | exit(); 28 | } 29 | 30 | // Mengambil token 31 | list(, $token) = explode(' ', $headers['Authorization']); 32 | 33 | try { 34 | // Men-decode token. Dalam library ini juga sudah sekaligus memverfikasinya 35 | JWT::decode($token, $_ENV['ACCESS_TOKEN_SECRET'], ['HS256']); 36 | 37 | $user = [ 38 | 'name' => 'John Doe', 39 | 'email' => 'johndoe@example.com' 40 | ]; 41 | 42 | echo json_encode($user); 43 | } catch (Exception $e) { 44 | // Bagian ini akan jalan jika terdapat error saat JWT diverifikasi atau di-decode 45 | http_response_code(401); 46 | exit(); 47 | } 48 | -------------------------------------------------------------------------------- /refresh-token.php: -------------------------------------------------------------------------------- 1 | load(); 12 | 13 | // Atur jenis response 14 | header('Content-Type: application/json'); 15 | 16 | // Cek method request 17 | if ($_SERVER['REQUEST_METHOD'] !== 'GET') { 18 | http_response_code(405); 19 | exit(); 20 | } 21 | 22 | // Cek cookie refreshToken 23 | if(!isset($_COOKIE['refreshToken'])) { 24 | http_response_code(403); 25 | exit(); 26 | } 27 | 28 | try { 29 | // Men-decode token. Dalam library ini juga sudah sekaligus memverfikasinya 30 | $refresh_payload = JWT::decode($_COOKIE['refreshToken'], $_ENV['REFRESH_TOKEN_SECRET'], ['HS256']); 31 | 32 | $waktu_kadaluarsa = time() + (15 * 60); 33 | 34 | // Payload untuk token baru 35 | $payload = [ 36 | 'email' => $refresh_payload->email, 37 | // Di library ini wajib menambah key exp untuk mengatur masa berlaku token 38 | 'exp' => $waktu_kadaluarsa 39 | ]; 40 | 41 | // Men-generate access token 42 | $access_token = JWT::encode($payload, $_ENV['ACCESS_TOKEN_SECRET']); 43 | 44 | // Kirim token ke user 45 | echo json_encode([ 46 | 'accessToken' => $access_token, 47 | 'expiry' => date(DATE_ISO8601, $waktu_kadaluarsa) 48 | ]); 49 | 50 | $payload['exp'] = time() + (60 * 60); 51 | $refresh_token = JWT::encode($payload, $_ENV['REFRESH_TOKEN_SECRET']); 52 | 53 | // Simpan refresh token baru di http-only cookie 54 | setcookie('refreshToken', $refresh_token, $payload['exp'], '', '', false, true); 55 | } catch (Exception $e) { 56 | // Bagian ini akan jalan jika terdapat error saat JWT diverifikasi atau di-decode 57 | http_response_code(401); 58 | exit(); 59 | } 60 | --------------------------------------------------------------------------------