類型->功能->有效時間->儲存位置
Access Token->每次呼叫 API 時使用的臨時身分證->約 15 分鐘->localStorage 或記憶體
Refresh Token->用來更新 Access Token 的憑證->可達數小時或數天->安全地存在後端或 httpOnly cookie
access_token
和refresh_token
access_token
access_token
過期時,後端回傳401 Unauthorized
refresh_token
向後端換新 Token專案結構
token-refresh-demo/
├── index.html
├── style.css
└── app.js
index.html
<!DOCTYPE html>
<html lang="zh-Hant">
<head>
<meta charset="UTF-8">
<title>Token 自動刷新 Demo</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<h1>🔐 Token 自動刷新示範</h1>
<button id="loginBtn">登入取得 Token</button>
<button id="apiBtn" disabled>呼叫受保護 API</button>
<button id="logoutBtn" disabled>登出</button>
<div id="output"></div>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script src="app.js"></script>
</body>
</html>
style.css
body {
font-family: Arial, sans-serif;
text-align: center;
margin-top: 60px;
}
button {
padding: 10px 15px;
margin: 5px;
cursor: pointer;
}
#output {
margin-top: 20px;
padding: 15px;
border: 1px solid #ddd;
width: 60%;
margin-left: auto;
margin-right: auto;
border-radius: 8px;
background-color: #f9f9f9;
}
app.js
const output = document.getElementById('output');
const loginBtn = document.getElementById('loginBtn');
const apiBtn = document.getElementById('apiBtn');
const logoutBtn = document.getElementById('logoutBtn');
// 模擬 Token 儲存
let accessToken = null;
let refreshToken = null;
let tokenExpireTime = null;
// 模擬登入取得 Token
loginBtn.addEventListener('click', async () => {
// 模擬登入成功
accessToken = "ACCESS_" + Math.random().toString(36).substr(2);
refreshToken = "REFRESH_" + Math.random().toString(36).substr(2);
tokenExpireTime = Date.now() + 10000; // Token 10 秒過期
output.innerHTML = `
<p>登入成功 🎉</p>
<p>Access Token: ${accessToken}</p>
<p>有效期限:10 秒</p>
`;
apiBtn.disabled = false;
logoutBtn.disabled = false;
});
// 模擬呼叫受保護 API
apiBtn.addEventListener('click', async () => {
if (Date.now() > tokenExpireTime) {
output.innerHTML += `<p>⚠️ Access Token 已過期,嘗試刷新中...</p>`;
await refreshAccessToken();
}
// 模擬 API 呼叫
output.innerHTML += `<p>✅ 使用 Token 成功呼叫 API (${new Date().toLocaleTimeString()})</p>`;
});
// 模擬刷新 Token
async function refreshAccessToken() {
return new Promise((resolve) => {
setTimeout(() => {
accessToken = "ACCESS_" + Math.random().toString(36).substr(2);
tokenExpireTime = Date.now() + 10000; // 新的 Token 再延長 10 秒
output.innerHTML += `<p>🔁 Token 已刷新成功:${accessToken}</p>`;
resolve();
}, 1500);
});
}
// 登出
logoutBtn.addEventListener('click', () => {
accessToken = null;
refreshToken = null;
tokenExpireTime = null;
output.innerHTML = `<p>已登出。</p>`;
apiBtn.disabled = true;
logoutBtn.disabled = true;
});
axios
攔截器(interceptor)自動檢查 Token 是否過期。