JWT認証について

## JWTとは
JWTとは、Json Web Tokenの略です。

トークンベース認証について学んでいきます。

トークンベース認証の特徴は、
セッションベース認証と違い、ログイン状態を保持・管理しません。

なのにどうやって、ユーザーを認証するのでしょうか？不思議ですよね。

ユーザーはログインや情報を取得するときなどに、
毎回このJWTをリクエストに持たせて送ります。
受け取ったアプリケーションはJWTを確認して有効か無効かを判断します。

一見何がメリットなのかわかりませんが順番に理解していきましょう。

## JWTのメリット（なぜJWTを使うのか）
- アプリケーションからすると、ログイン情報を管理しないで（パスワードなど）済むので、とてもシンプル。
- 署名というものをつかうので、改ざんされても検知できる。
- ユーザー権限も細かく設定ができる。
- 『シングルサインオン』という仕組みを使える。

## 構成
- ヘッダ
- ペイロード
- 署名
の３つが`.`で区切られています

```
　ヘッダ　｜　ペイロード　｜　署名
○○○○○○○○　   .○○○○○○○○　  .○○○○○○○○
```

**ヘッダ**

ヘッダには以下のような説明が明記されています
alg = 署名に使うアルゴリズム
typ = トークンのタイプ

```:ヘッダ
{
    "alg": "HJJHH"（←適当です）
    "typ": "JWT"
}
```

**ペイロード**
ペイロードには以下のような情報が明記されています。
sub = ユーザーを一意に特定するための識別子
exp = トークンの有効期限

**パスワードが入らないことに注意してください。エンコードしますが、この部分を盗まれてしまったらデコードして簡単にみられてしまいますので。そもそもJWT認証を使う意味がなくなります。**

```:ペイロード
{
    "sub": "12345"（←適当です）
    "exp": "678910"（←適当です）
}
```

**JWT前半**
以下のように、ヘッダ・ペイロードの情報をエンコードします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3895655/0db46250-2a38-7fdc-5c87-98d486e69536.png)

**JWT後半**
次に、署名を秘密鍵で行います。この時にヘッダの`alg`を使います。
それをさらにエンコードします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3895655/151e1244-9977-26e8-0d08-fb897893dac8.png)


**JWT全体**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3895655/9f4f79ae-87b8-752a-7dae-5b28264fe4d3.png)

## JWTの仕組み
JWTがどのようなものかイメージ出来たとおもいます。

では、JWTがどのような役割を担い、
どのように機能するのかさらに詳しく知っていきましょう。

きずいたと思いますが、JWTは中身を見ることができます。
そこはあまり重要ではなく、見られても改ざんされなければよいわけです。

**つまり、JWTは改ざんを検知する仕組みと言えます。**

JWTの後半の署名部分は秘密鍵を知らなければ元の状態には戻せないので、
本当の意味で中身を見られません。

では、このJWTをユーザーとアプリケーションがどのように検証するか
さらに解像度上げていきましょう。

## JWTの作成・認証のながれ


### 共通鍵方式 (後ほど公開鍵方式説明します。）

例えば、みなさんが普段なにかのサービスにアクセスする際を考えてみます。

### JWTの作成
- ユーザーは、新規登録または登録済みのユーザーIDとパスワードでアプリケーションにログインします。
- アプリケーションは、ユーザーIDとパスワードが正しいかどうかをデータベースと照らし合わせて確認します。
- 一致すれば、アプリケーションは、ユーザーIDなどを使ってJWTを作成します。
- JWTの署名には、アプリケーションだけが持っている秘密鍵を使います。
- アプリケーションは作成したJWTをユーザーに渡します。
- JWTはユーザーのブラウザなどに保存されます。

どうでしょうか？なんとなくイメージわきませんか？普段何気なくやっていることです。
以下の画像でさらにイメージを沸かせましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3895655/229c9ba5-7a04-a7d7-5b90-4f6143236910.png)


### JWTの認証
ユーザーは、前回ログインしたときにJWTを受取って持っている状態だとします。その場合はユーザーIDとパスワードを入力せずとも、リクエストにJWTを含めて送ることでログインやエンドポイントへのアクセスができます。
以下がその流れです。

- JWTを持っているユーザーは、次にアプリケーションにログインする時やリクエストを送る時、リクエストの都度JWTを含めて送ります。
- ユーザーからリクエストが来たら、アプリケーションは秘密鍵を使って、JWTが有効か検証します。
- 検証して有効であれば、アプリケーションはユーザーにレスポンスを返します。

以下の画像でさらにイメージを沸かせましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3895655/da741bb7-fece-7942-cb2a-6575f5f2c922.png)


### 共通鍵方式
これこそまさに日常でとても使っています。

例えば、なにかのアプリに新規登録やログインする際に、
Googleでログイン
AppleIDでログイン
Yahoo!JAPANでログイン
メールアドレスでログイン
みたいなのよくありませんか？

今から説明する公開鍵をつかった認証のながれは、
この『シングルサインオン』という仕組みを使っています。

上記を理解できれば似たようなものなのでそんなに難しくありません。
順番に行きましょう。（Googleを例にいきますね）

### JWTの作成
Googleに、ユーザーIDとパスワードを入力して新規登録やログインします。
ログインに成功すると、GoogleがJWTを発行してユーザーに渡します。
以下がその流れです。

- ユーザーは、新規登録または登録済みのユーザーIDとパスワードで、Googleのサービスにログインを試みます。
 -Googleは、ユーザーIDとパスワードが正しいかどうかをデータベースと照らし合わせて確認します。
- 問題なければ、ユーザーIDなどを使ってJWTを作成します。
- JWTの署名には、Googleだけが持っている秘密鍵を使います。
- 作成したJWTをユーザーに渡します。
- JWTはユーザーのブラウザなどに保存されます。
(ほぼ一緒)


### JWTの認証（ここからが違います）
ユーザーは、GoogleにログインしたときにJWTを受取って持っている状態だとします。
その場合はアプリケーションに登録していなくても、
リクエストにJWTを含めて送ることでアプリケーションへ
ログインやエンドポイントへのアクセスができます。（どういうこと？てなる）
以下がその流れです。

- JWTを持っているユーザーは、アプリケーションにログインする時やリクエストを送る時、リクエストの都度JWTを含めて送ります。
- ユーザーからリクエストが来たら、アプリケーションはGoogle公開鍵をリクエストします。
- Googleは公開鍵を渡します。
- アプリケーションは公開鍵を使って、JWTが有効か検証します。
- 検証して有効であれば、アプリケーションはユーザーにレスポンスを返します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3895655/f5a6a2a6-a065-d2c8-f2cc-0051ad407501.png)