使用原生 JS 語法將 JWT exp 日期轉換成正常時間

前言

JWT(Json Web Token) 目前已廣泛應用了,可以很方便地用於無狀態協議(stateless)的 http api 使用

而簽出後,自帶 iat(issue at,發出日期)、exp(expires,有效日) 便於前端判斷 token 有效期限
本身又是單純以 base64 編碼,故 Client 端可以很輕鬆的解回來查看相關資訊( jwt 官方建議不應在 token 裡埋藏太多資訊)

解回來後,會發現iat, exp日期都是以純數字保存,需再做一層日期轉換,才能取得正確時間

將JWT iat, exp 轉換回正常時間(純js)

npm 上其實有不少現成套件(如jwt-decode)可以直接轉換回來
但對前端來說,本身就有現成的語法,其實不太需要特地再下載一個套件
僅須短短2行程式碼即可取得時間,也可以讓前端更輕量些!
(亦可精簡成一行,只是較不易閱讀)

1
2
const payload = JSON.parse(atob(token.split('.')[1]));
const expDate = new Date(new Date(0).setUTCSeconds(payload.exp)); // 得到正常的js日期時間

補充說明:
btoa(binary to ascii, 編碼)、atob(ascii to binary, 解碼)是瀏覽器提供的base64編碼、解碼的函式(Web API)

補充:使用dayjs判斷 token 是否到期並取得新的 token(Angular)

由於moment.js作者已宣佈不維護,加上後起之秀dayjs興起,僅2kb大小的日期處理套件!
現在前端比較流行的應是dayjs
若仍是使用moment.js也沒關係,用法基本上一樣!

提供 Angular 範例
使用dayjs判斷 token 是否到期,若接近到期,則取得新 token

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import * as dayjs from 'dayjs';

// 須依自己在jwt放入的資料調整interface格式
interface JwtPayload {
username: string;
sub: string;
iat: number;
exp: number;
}

// ....
// 省略 Angular class部份,僅貼上 function
// ...

private refreshToken(token: string): void {
const payload: JwtPayload = JSON.parse(atob(token.split('.')[1])) as JwtPayload;
const expDate = dayjs(new Date(0).setUTCSeconds(payload.exp)); // 僅將最外層的`new Date`改成`dayjs`即可無痛轉換成`dayjs`格式
const current = dayjs();

if (current.isAfter(expDate.subtract(5, 'minutes'))) {
this.http.get<{token: string}>(`/api/refresh/token`).subscribe({
next: res => this.saveToken(res.token), // 將 token 更新回 Angular 的 authService 與 localStorage 或 cookie,依需求自行調整
error: (err: HttpErrorResponse) => console.log(err)
});
}

參考資料

Stack Overflow / Transform Tick to Date in JS
程式前沿 / JavaScript用btoa和atob來編碼解碼Base64