Skip to content

Commit

Permalink
feat: pengecekan apakah token kedaluarsa (#1)
Browse files Browse the repository at this point in the history
  • Loading branch information
priyadi authored Mar 6, 2024
1 parent 928322a commit a21978d
Show file tree
Hide file tree
Showing 9 changed files with 117 additions and 10 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
\?
composer.lock
vendor/
.phpunit.cache
tools
.php-cs-fixer.cache
var
var
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# CHANGELOG

## 0.6.0

* feat: pengecekan apakah token kedaluarsa

## 0.5.0

* Initial release
9 changes: 9 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
PHP=php
COMPOSER=composer
PLANTUML=docker run --rm --user $$(id -u):$$(id -g) -v ./:/data/ plantuml/plantuml
WSD_FILES=$(wildcard docs/*.wsd)

.PHONY: test
test: dump phpstan psalm phpunit
Expand Down Expand Up @@ -29,3 +31,10 @@ php-cs-fixer: tools/php-cs-fixer
.PHONY: tools/php-cs-fixer
tools/php-cs-fixer:
phive install php-cs-fixer

.PHONY: docs/%.svg
docs/%.svg: docs/%.wsd
$(PLANTUML) -tsvg $< -o ./

.PHONY: diagrams
diagrams: $(WSD_FILES:docs/%.wsd=docs/%.svg)
35 changes: 28 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
# clarus-it/http-client

Contoh HTTP client untuk keperluan mengakses API ke aplikasi-aplikasi buatan
Clarus IT.
Library HTTP client dalam bahasa pemrograman PHP untuk keperluan mengakses API
ke aplikasi-aplikasi buatan Clarus IT. Library ini berlaku sebagai reference
implementation dan contoh bagi yang perlu membuat implementasi untuk bahasa
pemrograman lain.

## Contoh Penggunaan
## Instalasi

Untuk menginstall library ini, bisa menggunakan composer:

```bash
composer require clarus-it/http-client
```

## Penggunaan

Berikut contoh penggunaan `ClarusHttpClient`:

Expand All @@ -19,7 +29,7 @@ $client = new ClarusHttpClient($apiKey, $baseUri);

// melakukan request GET ke https://example.com/api/ping
// client akan secara otomatis melakukan login apabila belum login, atau jika
// tokennya sudah kadaluwarsa
// tokennya sudah kedaluarsa
$response = $client->request('GET', 'ping');

// mendapatkan hasilnya sebagai array
Expand All @@ -31,15 +41,26 @@ digunakan dengan cara yang sama dengan Symfony HttpClient.

## Algoritma

![Diagram proses](docs/proses.png?raw=true "Title")
Algoritma operasional HTTP client ini adalah sebagai berikut.

## Bahasa Pemrograman Lain
![Diagram proses](docs/proses.svg?raw=true "Title")

Catatan: Bagian pengecekan apakah token kedaluarsa sebenarnya boleh saja tidak
diimplementasikan. Konsekuensinya, library hanya dapat tahu token sudah
kedaluarsa setelah melakukan request ke server.

## Pembuatan Implementasi Dalam Bahasa Pemrograman Lain

Pada bahasa pemrograman lain seharusnya tidak sulit untuk mengimplementasikan
HTTP client ini. Untuk contoh, bisa melihat pada file
[ClarusHttpClient.php](./src/ClarusHttpClient.php) dan mengadaptasikan ke bahasa
pemrograman lain tersebut.

## License
Untuk keperluan parsing JWT, bisa menggunakan library yang ada di bahasa
pemrograman yang digunakan. Daftar library bisa dilihat di
[jwt.io](https://jwt.io/libraries). Yang diperlukan untuk kasus ini adalah
library yang dapat melakukan `exp` check.

## Lisensi

MIT
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
],
"require": {
"php": ">=8.2",
"lcobucci/jwt": "^5.2",
"symfony/http-client": "^6.4 || ^7.0"
},
"require-dev": {
Expand Down
Binary file removed docs/proses.png
Binary file not shown.
1 change: 1 addition & 0 deletions docs/proses.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 8 additions & 2 deletions docs/proses.wsd
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,19 @@ start

:melakukan request API;

partition library API client {
if (apakah sudah\nada token?) then (tidak)
partition library HTTP client {
if (apakah sudah\nmemiliki token?) then (tidak)
:lakukan login untuk
mendapatkan token;
else (ya)
endif

if (apakah token\nsudah kedaluarsa\natau sebentar lagi\nakan kedaluarsa?) then (ya)
:lakukan login ulang untuk
mendapatkan token;
else (tidak)
endif

:lakukan request
menggunakan token;

Expand Down
64 changes: 64 additions & 0 deletions src/ClarusHttpClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,18 @@

namespace ClarusIt\HttpClient;

use Lcobucci\JWT\Encoding\JoseEncoder;
use Lcobucci\JWT\Token\Parser;
use Lcobucci\JWT\UnencryptedToken;
use Symfony\Component\HttpClient\HttpClient;
use Symfony\Contracts\HttpClient\HttpClientInterface;
use Symfony\Contracts\HttpClient\ResponseInterface;
use Symfony\Contracts\HttpClient\ResponseStreamInterface;

final class ClarusHttpClient implements HttpClientInterface
{
const TIME_COMPENSATION = 300;

/**
* API Key yang didapatkan dari aplikasi
*/
Expand All @@ -35,6 +40,11 @@ final class ClarusHttpClient implements HttpClientInterface
*/
private HttpClientInterface $client;

/**
* Parser untuk JWT token
*/
private Parser $parser;

/**
* @param string $apiKey API Key yang didapat dari aplikasi
* @param string $baseUrl Base URL, termasuk path /api/ di akhir, misalnya
Expand All @@ -50,6 +60,7 @@ public function __construct(
) {
$this->apiKey = $apiKey;
$this->client = $client ?? HttpClient::create();
$this->parser = new Parser(new JoseEncoder());

$this->client = $this->client->withOptions(
[
Expand Down Expand Up @@ -80,6 +91,13 @@ public function request(
$this->login();
}

// jika token yang kita miliki sudah kedaluarsa atau sebentar lagi akan
// kedaluarsa, maka kita lakukan login ulang.

if ($this->isTokenExpired()) {
$this->login();
}

// lakukan request ke API berdasarkan method, url, dan options yang
// diberikan

Expand Down Expand Up @@ -147,6 +165,52 @@ private function login(): void
$this->token = $token;
}

/**
* Menghitung apakah token yang kita miliki saat ini sudah kedaluarsa, atau
* sebentar lagi kedaluarsa
*/
private function isTokenExpired(): bool
{
// jika token tidak ada, maka dianggap sudah kedaluarsa

if ($this->token === null || $this->token === '') {
return true;
}

// parse token yang kita miliki

$token = $this->parser->parse($this->token);

// jika token yang kita miliki bukan instance dari UnencryptedToken,
// maka dianggap sudah kedaluarsa

if (!$token instanceof UnencryptedToken) {
return true;
}

// ambil claims dari token

$claims = $token->claims();

// ambil nilai `exp` dari claims

$exp = $claims->get('exp');

// jika nilai `exp` tidak ada, atau bukan integer, maka dianggap sudah
// kedaluarsa

if (!is_int($exp)) {
return true;
}

// jika waktu kedaluarsa dari token kurang dari waktu sekarang dikurangi
// dengan TIME_COMPENSATION, maka dianggap sudah kedaluarsa. jadi jika
// token expire pukul 10:00, maka token dianggap sudah kedaluarsa pukul
// 09:55

return $exp < time() - self::TIME_COMPENSATION;
}

/**
* Tidak digunakan, silakan diabaikan saja
*/
Expand Down

0 comments on commit a21978d

Please sign in to comment.