# Token-Based Authentication JWT
## JWT 介紹
1. JSON Web Token (JWT) 是一種基於 JSON 的開放標準(RFC 7519),基於 JSON object 的編碼,並透過這個編碼進行傳遞資訊。
2. JWT會透過HMAC、RSA、ECDS等演算法進行加密
[https://jwt.io/](https://jwt.io/)
## JWT 組成
JWT 分為 Header, Payload, Signature 三個部份以 Base64 編碼, 並且以 . 分開。
eg: `xxxxx.yyyyy.zzzzz`
* **Header**
Header 由 alg, typ 兩個欄位所組成
1. alg: Signature 所要使用的加密演算法
2. typ: token 種類,基本上是 JWT
eg:
```json=
{
"alg": "HS256",
"typ": "JWT"
}
```
* **Payload**
Payload 是用來傳送訊息(claim)的地方(也可以空白),主要有三種內容
1. Registered claims: 一些已經標準公認的訊息,建議放,但不強迫
* iss: JWT簽發者
* iat: JWT簽發時間
* exp: JWT的過期時間
* ...
2. Public claims: 可以向官方申請公開聲明
3. Private claims: 自定義的訊息
eg:
```json=
{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}
```
:::warning
**由於加密只作用於 Signature ,因此 Payload 不應該存放隱私資訊**
:::
* **Signature**
Signature 由三個部份組成
1. base64UrlEncode(header)
2. base64UrlEncode(payload)
3. secret
```
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
```
signature 是用來確保訊息不會在傳送途中被竄改,並且有一個 private secret key 用來確保 JWT 發行者的正確性
## JWT 使用
* 流程

* client 端使用方法
當使用需要驗證的 api 時,在 Authorization header 使用 Bearer schema
```
Authorization: Bearer <token>
```
## Server 範例
``` javascript
import jsonwebtoken from "jsonwebtoken";
import express, { urlencoded } from "express";
import "dotenv/config";
const app = express();
app.use(urlencoded({ extended: true }));
app.post("/login", async (req, res, next) => {
const { id } = req.body;
const token = jsonwebtoken.sign({ id: id }, process.env.JWT_SIGN_SECRET, {
noTimestamp: true,
algorithm: process.env.JWT_ALGO,
});
return res.status(200).json({ jwt: token });
});
app.get("/hello", async (req, res, next) => {
try {
const token = req.header("Authorization").replace("Bearer ", "");
const decoded = jsonwebtoken.verify(token, process.env.JWT_SIGN_SECRET, {
algorithm: process.env.JWT_ALGO,
});
return res.status(200).send(`Hello ${decoded.id}`);
} catch (e) {
return res.status(404).send({ error: "Please authenticate." });
}
});
app.listen(8080, () => {
console.log(`
################################################
🛡️ HTTP server listening on port: 8080 🛡️
################################################
`);
});
```
## JWT with Nginx
[https://github.com/TeslaGov/ngx-http-auth-jwt-module](https://github.com/TeslaGov/ngx-http-auth-jwt-module)
[https://github.com/auth0/nginx-jwt](https://github.com/auth0/nginx-jwt)
待更新
## 流程

```javascript=
import express, { Router, urlencoded, json } from "express";
import { createProxyMiddleware } from "http-proxy-middleware";
import jsonwebtoken from "jsonwebtoken";
import morgan from "morgan";
// Create Express Server
const app = express();
// Configuration
const PORT = 3000;
const HOST = "localhost";
const API_SERVICE_URL = "http://127.0.0.1:4444/";
const route = Router();
app.post("/login", async (req, res, next) => {
const { id } = req.body;
const token = jsonwebtoken.sign({ id: id }, "ABCDEFG");
return res.status(200).json({ jwt: token });
});
// Proxy endpoints
app.use("/wd/hub/session/", morgan("common"), route);
route.post(
"/",
createProxyMiddleware({
target: API_SERVICE_URL,
changeOrigin: true,
onProxyReq(proxyReq, req, res) {
try {
let data = "";
let token;
req.on("data", (chunk) => {
data += chunk;
});
req.on("end", () => {
//console.log(JSON.parse(data).capabilities.auth);
token = JSON.parse(data).capabilities.auth;
console.log(token);
jsonwebtoken.verify(token, "ABCDEFG");
proxyReq.end();
});
proxyReq.setHeader("content-type", "application/json; charset=utf-8");
proxyReq.write(data);
} catch (e) {
console.log(e);
return res.status(404).send({ error: "Please authenticate." });
}
},
})
);
route.post(
"/:id",
morgan("common"),
createProxyMiddleware({
target: API_SERVICE_URL,
changeOrigin: true,
})
);
// Start Proxy
app.listen(PORT, HOST, () => {
console.log(`Starting Proxy at ${HOST}:${PORT}`);
});
```
###### tags: JWT Nginx