0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

OpenSSLで作成した署名鍵を利用したIDトークン生成/検証エンドポイントの作成方法 メモ

Posted at

①署名鍵生成

  • opensslを利用して秘密鍵/署名鍵を生成

    openssl genrsa -out private-key.pem 2048
    openssl rsa -in private-key.pem -pubout -out public-key.pem
    

②公開鍵をJWK形式に変換

  • jsライブラリpem-jwkを利用して、JWK形式に変換する。※もっとスマートな方法があれば...

  • generate_jwk.js

    var fs = require('fs')
    var pem2jwk = require('pem-jwk').pem2jwk
    var str = fs.readFileSync('./public-key.pem', 'ascii')
    var jwk = pem2jwk(str)
    console.log(jwk)
    
    node generate_jwk.js
    {
      kty: 'RSA',
      n: 'pw5We-LHJAIXSOwNbUxO8T615XgNn8e1J_1auE8Nza9MEkSWqf1ylz1MnOoPWqnnleo0mJfAza2Ro5xm7aKUGtPVwThwGj32SUtYj5mYPd3kfVgO9colc9k_dle8OpcP54CoA-5fVd24jt-jL3SXcITxB2-9-ms2gyTZnPjTaEeXCa6ElyMiHjcw4VApwzmZsu6wkCW4uPnX-_uZvxwjcGEH9RKMyWU0B5m_NOKcgy9eChZMw01rAxlxDugvvEU0iedzuAUu3vv19tn1UOvIUToyXrhUw0PSEr_nUg_zITVf-IjZ6yqKgI_2HU37AypypIe8TsjmgHwSP49X2MnUmQ',
      e: 'AQAB'
    }
    

③エンドポイント作成

プロジェクト構成

test	--- docker-compose.yml
		 |_ 	app		- 	Dockerfile
		 				|_	requirements.txt
		 				|_	main.py
		 				|_	private-key.pem※前述の手順で生成したもの

コード・設定ファイル類

main.py
  • FastAPIを使用して各種エンドポイントを作成する。
from fastapi import FastAPI,Form
from starlette.requests import Request
from starlette.responses import RedirectResponse
import jwt
from jwt import PyJWKClient
from pydantic import BaseModel
import datetime
from datetime import datetime, timedelta
import time

# リクエストbody定義
class IdToken(BaseModel):
    id_token: str

# JWK,IDトークン要素
KID = "12345"
USE = "sig"
ALG = "RS256"
ISS = "http://server.example.com"
SUB = "248289761001"
AUD = "s6BhdRkqt3"

app = FastAPI()

# JWKSエンドポイント
@app.get("/auth/jwks")
def jwks():
    # 「公開鍵をJWK形式に変換」の取得結果にkid,use,algを追加
    return {
        "keys":[{
            "kid":KID,
            "use":USE,
            "alg":ALG,
            "kty": "RSA",
            "n": "pw5We-LHJAIXSOwNbUxO8T615XgNn8e1J_1auE8Nza9MEkSWqf1ylz1MnOoPWqnnleo0mJfAza2Ro5xm7aKUGtPVwThwGj32SUtYj5mYPd3kfVgO9colc9k_dle8OpcP54CoA-5fVd24jt-jL3SXcITxB2-9-ms2gyTZnPjTaEeXCa6ElyMiHjcw4VApwzmZsu6wkCW4uPnX-_uZvxwjcGEH9RKMyWU0B5m_NOKcgy9eChZMw01rAxlxDugvvEU0iedzuAUu3vv19tn1UOvIUToyXrhUw0PSEr_nUg_zITVf-IjZ6yqKgI_2HU37AypypIe8TsjmgHwSP49X2MnUmQ",
            "e": "AQAB"
        }]
    }

# IDトークン生成エンドポイント
@app.get("/auth/generate_id_token")
def generate_it_token():
    # 署名用秘密鍵
    with open('./private-key.pem') as f_private:
        private_key = f_private.read()
    # ヘッダー部
    header = {
        "kid":KID,
        "alg":ALG
    }
    # ペイロード部
    payload = {
        "iss":ISS,
        "aud":AUD,
        "sub":SUB,
        "exp":int(time.mktime((datetime.now() + timedelta(days=1)).timetuple())),
        "iat":int(time.mktime(datetime.now().timetuple()))
    }
    id_token = jwt.encode(payload, private_key,
                         algorithm='RS256', headers=header)
    return {
        "id_token":id_token
    }

# IDトークン検証エンドポイント
@app.post("/auth/verify_id_token")
def verify_id_token(idToken: IdToken):
    # ローカルJWKSエンドポイントURL
    url = "http://localhost:8000/auth/jwks"
    jwks_client = PyJWKClient(url)
    public_key = jwks_client.get_signing_key_from_jwt(idToken.id_token)
    payload = jwt.decode(idToken.id_token, public_key.key, algorithms=["RS256"], audience=AUD)
    return payload

if __name__ == "__main__":
    uvicorn.run(app, port=8000, loop="asyncio")
Dockerfile
FROM python:3.8

WORKDIR /usr/src/server
ADD requirements.txt .
ADD private-key.pem .
RUN pip install -r requirements.txt

# uvicornのオプションに--reloadを付与し、
# main.pyの編集と同時に変更内容を反映させる。
CMD ["uvicorn", "main:app", "--reload", "--host", "0.0.0.0", "--port", "8000"]
requirements.txt

※依存ライブラリ

fastapi
python-multipart
requests
uvicorn
cryptography
PyJWT
docker-compose.yml
version: "3.5"
networks:
  container-link:
    name: docker.internal
services:
  app:
    container_name: "app"
    build: ./app
    volumes:
      - ./app:/usr/src/server
    ports:
      - "8000:8000"
    networks:
      - container-link

動作確認

起動

docker-compose up -d

IDトークン生成エンドポイント

  • リクエスト

    GET /auth/generate_id_token HTTP/1.1
    Host: 127.0.0.1:8000
    Cache-Control: no-cache
    Postman-Token: 438dbc81-196c-9983-dce2-8e8875680b18
    
  • レスポンス

    {
        "id_token": "eyJ0eXAiOiJ...Y3fDPOg"
    }
    

IDトークン検証エンドポイント

  • リクエスト

    POST /auth/verify_id_token HTTP/1.1
    Host: 127.0.0.1:8000
    Content-Type: application/json
    Cache-Control: no-cache
    Postman-Token: 1a357704-50f8-256e-5821-347114829cec
    
    {
        "id_token": "eyJ0eXAiOiJKV1Q...3rHY3fDPOg"
    }
    
  • レスポンス

    {
        "iss": "http://server.example.com",
        "aud": "s6BhdRkqt3",
        "sub": "248289761001",
        "exp": 1648722999,
        "iat": 1648636599
    }
    

JWKSエンドポイント

  • リクエスト

    GET /auth/jwks HTTP/1.1
    Host: 127.0.0.1:8000
    Cache-Control: no-cache
    Postman-Token: 5902c2a7-0337-f43e-0f71-c448d22ee3c8
    
  • レスポンス

    {
        "keys": [
            {
                "kid": "12345",
                "use": "sig",
                "alg": "RS256",
                "kty": "RSA",
                "n": "pw5We-LHJAIXSOwNbUxO8T615XgNn8e1J_1auE8Nza9MEkSWqf1ylz1MnOoPWqnnleo0mJfAza2Ro5xm7aKUGtPVwThwGj32SUtYj5mYPd3kfVgO9colc9k_dle8OpcP54CoA-5fVd24jt-jL3SXcITxB2-9-ms2gyTZnPjTaEeXCa6ElyMiHjcw4VApwzmZsu6wkCW4uPnX-_uZvxwjcGEH9RKMyWU0B5m_NOKcgy9eChZMw01rAxlxDugvvEU0iedzuAUu3vv19tn1UOvIUToyXrhUw0PSEr_nUg_zITVf-IjZ6yqKgI_2HU37AypypIe8TsjmgHwSP49X2MnUmQ",
                "e": "AQAB"
            }
        ]
    }
    

参考情報

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?