はじめに
皆さんこんにちは!
新卒一年目の宮村です!
現在の業務では、主にOpenID Connect(OIDC)を使用した基幹システムを運用しています。
そのため今回は、業務を通じて学んだOIDCの基礎について発信していきたいと思います。
この記事の前提
今回のハンズオンはWindowsのPowerShellを前提にしています。
おそらく、MacやLinuxでも動作すると考えておりますが、保証はできません。
以下の記事等を閲覧し、OIDCの概要がわかっている前提で説明します。
https://qiita.com/TakahikoKawasaki/items/498ca08bbfcc341691fe
ハンズオン準備
今回使用するソースコードのクローン
まず、準備として今回使用するOIDCのサーバーdjango-oidc-providerをGit cloneし、exampleディレクトリに移動します。
1 2 |
$ git clone https://github.com/juanifioren/django-oidc-provider.git $ cd django-oidc-provider/example |
このexampleディレクトリには、実際にdjango-oidc-providerを導入した際のOpenID Provider(OP)の実装例があります。
Dockerコンテナの作成
exampleが少し古くそのままでは動かなかった点と今回のハンズオンの都合上、DockerFileの内容を以下に変更してください。
※あくまでテストであるため、スーパーユーザー情報をファイルに直書きしています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
FROM python:3.10 WORKDIR /app COPY . /app RUN pip install --upgrade pip RUN pip install --no-cache-dir -r requirements.txt RUN python manage.py migrate RUN python manage.py creatersakey # 環境変数でデフォルトのスーパーユーザー情報を設定 ENV DJANGO_SUPERUSER_USERNAME=admin ENV DJANGO_SUPERUSER_EMAIL=admin@example.com ENV DJANGO_SUPERUSER_PASSWORD=admin # スーパーユーザーを作成(既存の場合はスキップ) RUN python manage.py createsuperuser --noinput || echo "Superuser already exists" EXPOSE 8000 CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"] |
以下のコマンドで実際に起動してみましょう!
1 2 |
$ docker build -t django-oidc-provider . $ docker run -d -p 8000:8000 django-oidc-provider |
http://localhost:8000で以下の画像が確認出来たら成功です。

テストClientの追加
Create your clients
をクリックしましょう。
ここでいうclientはOPを使用するクライアントのことを指し、Relying Party(RP)とも呼ばれます。
クリック後、ログイン画面が表示されるため、ID、パスワードどちらもadmin
を入力しましょう。
ログイン後は左サイドバーのClientsの隣にある+Add
をクリックします。
その後、以下を入力します。(それ以外はそのままでOKです)
- Name: テスト
- Response types
- code
- id_token
- id_token token
- Redirect URIs: http://example.com
- Scopes: openid profile email address phone
入力例


この後、Saveをクリックし、生成したclientを確認すると以下のようにClient IDとClient Secretが自動生成されたことが確認できます(以下はあくまで例です)。
これらの情報は、リクエストを送信したclientが正規のclientであることをOPが確認するために使用します。
この後のハンズオンで使用するため、これらの情報をメモしておきましょう。

テストユーザの作成
左サイドバーのUsersの隣にある+Add
をクリックします。
すると、以下の画面に遷移するため、以下の情報を入力しSaveをクリックします
- Username: test_user01
- password: test_user01

すると、以下の画面へ遷移するため
First name: user01
Last name: test
Email address: example@google.com
と入力しSaveをクリックします。
これで、下準備は完了しました。

ハンズオン
実際に設定したOPに対してログインしてみましょう。
今回は、OIDCのシーケンスの中で最も一般的なAuthorization Code Flowで試してみます。
ログイン(Authorization Request)
初めにブラウザのシークレットブラウザモードを立ち上げ、以下のURLを張り付けてください。
1 |
http://localhost:8000/authorize/?client_id=【先ほど生成されたClient ID】&redirect_uri=http://example.com&response_type=code&state=123456&scope=openid+profile+email |
このURLは、OPに対して認可コードの発行を要求するAuthorization Requestです。
ここでは、/authorize
エンドポイントを指定していますが、エンドポイントがどのURLに存在するかの情報は、.well-known/openid-configurationを参照すれば知ることができます。
実際にブラウザでアクセスしてみると、今回使用する authorization_endpoint
等のURLが記載されているのが確認できます。これはOIDCのDiscovery(発見)機能と呼ばれます。
以下に主要なパラメータの詳細を一部抜粋して説明します。
client_id
: client(RP)の識別子redirect_uri
: 認証終了後にリダイレクトされるURI。response_type
: 認証後にどの情報を返すか(Authorization Code Flowだとcodeを指定)scope
: ClientがOPに要求したいユーザー情報の範囲(プロフィール、メールアドレスなど)を指定します。ここで要求したスコープに対応する情報が、後のUserInfoレスポンスで取得できます。
張り付けた後Enterを押すと、ログイン画面が表示されるため、先ほど作成したユーザでログインします。
以下の画面へ移動します。
この画面は、Clientに対して以下の情報を渡すことをユーザに対して許可を求めていることを意味します。
ここではAcceptをクリックします。

その後、example.comにリダイレクトします。
リダイレクトした際のURLパラメータに存在するcodeは認可コードのことを表し、トークンの発行に使用します。

この認可コードを使用して、実際にトークンを発行してみましょう。
以下のコマンドをPowerShellに張り付けましょう。
このコマンドはToken Requestを送信するものであり。OPに対してトークンの発行を申請します。
1 |
$ curl -s -X POST -H "Cache-Control: no-cache" -H "Content-Type: application/x-www-form-urlencoded" "http://localhost:8000/token/" -d "client_id=【先ほど生成されたClient ID】" -d "client_secret=【先ほど生成されたClient Secret】" -d "code=【発行された認可コード】" -d "state=123456" -d "redirect_uri=http://example.com" -d "grant_type=authorization_code" |
すると、以下の例のようなレスポンスが返ってきます。
1 2 3 4 5 6 7 |
{ "access_token": "df6e0afa50e14a879f151feda46295b7", "refresh_token": "d6649365913f4c56abefe3f2b8b8732d", "token_type": "bearer", "expires_in": 3600, "id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6Ijk1YjBmY2I5NDI4NTI1YjM0MGRlZWM4ZjJlNTFhYmNlIn0.eyJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwMDAiLCJzdWIiOiIxIiwiYXVkIjoiOTI0NDIyIiwiZXhwIjoxNzU0OTgxMTkwLCJpYXQiOjE3NTQ5ODA1OTAsImF1dGhfdGltZSI6MTc1NDk3NjE0MiwiYXRfaGFzaCI6ImlkRHRjVjdvYzl4Ny1yTFNoSTg5bHcifQ.fzlqjsHJycYrSx2EsGjsGsgLZC3z4mRVpKPATG0D_mU6bDD7ZLv4G3Sk5kXmibBekaLR5zBIUr84ZmQ77qo3CdARxLOn7rB4CLE3-9d-JEoQpwI9uHac3iQXdx6HVN2zBQJjm6CPkx8t0Z9-d1ErRzJiAeiJChPq4JbxsmtFJzgFwssdKeUdMwgsjR64wIY8uP9KV9NFG3X0vKfnAVSPdsp9QpfV68xkqwmhnotKHShSbDYsNPOAIGvryCxyb74h87BEVxk8OHmg79SsyXkf2eBpaA9ykg43EK-tMh2MZg3dfLqoFb0ZbUYgojJACMBsXAo9_WdF5MeEUczMsSs8HQ" } |
主要な部分を抜粋すると、
Access Token
: ユーザ情報を取得するために使用されるトークンです。Refresh Token
: ID TokenとAccess Tokenを再生成する際に使用されるトークンです。IDトークン
は: OPが正規なものであることと、ユーザーが認証されていることを証明するトークンです。
IDトークン検証
この後、ID Tokenの中身を検証し、OPが正規なものであるか確認します。今回は手動でIDトークンを検証しましょう。
以下のWebサイト(jwt.io)にID Tokenを張り付けてみましょう。
張り付けた後、以下の画面が右側表示されるはずです。

主要な部分を以下に抜粋します。
ヘッダー部分
alg
: 署名アルゴリズムkid
: 署名の検証に使用する鍵のid
ペイロード部分
iss
: ID Tokenの発行元でURLが表示されます。sub
: ユーザの識別子(ID)を示します。aud
: ID Tokenを使用するClientを示します。exp
: ID Tokenの有効期限(Unix time)at_hash
: アクセストークンをハッシュ化したもの。アクセストークンが正しいものかどうかを検証するために使用
これらの値を実際のものと見比べると正しいものであることを確認できるはずです。
また、IDトークンは.
で区切られた3つの部分(ヘッダー・ペイロード・署名)から構成されており、最後の部分が署名です。http://localhost:8000/jwksにアクセスすると署名の検証に使用する公開鍵の情報があります。
IDトークンの署名は、ヘッダーとペイロードを.
で連結したものから計算したハッシュ値を、OPが持つ秘密鍵で暗号化したものです。RP側では、OPの公開鍵を使ってこの署名を検証します。これにより、トークンが改ざんされておらず、確かにそのOPから発行されたものであることを確認できます。詳しい検証プロセスは複雑なため省略します。
※余談ですが、jwt.ioの仕様上ID Tokenから署名の検証に必要な公開鍵を、左下に自動で割り出してくれます。実際に、http://localhost:8000/jwksの情報と比較してみると一致するはずです。

UserInfo Request
IDトークンの検証が終了した後、実際にユーザ情報を取得します。
以下のコマンドをPowerShellで叩いてください。
1 |
$ curl -s -X GET -H "Authorization: Bearer 【発行されたアクセストークン】" "http://localhost:8000/userinfo/" |
すると、Authorization RequestのScopeで指定した、profile, emailの情報が取得できます。
1 2 3 4 5 6 7 |
{ "sub": "2", "given_name": "user01", "family_name": "test", "nickname": "test_user01", "email": "example@google.com" } |
最後に
OIDCはだいたい、このような流れとなっています。
今回は一連の流れを手作業で行いましたが、実際使用する際は、OIDCのClient用ライブラリを使用するため、OPのアドレス(issパラメータ)やClient ID, Client Secretさえ指定してしまえば、あとはほぼすべて自動でやってくれます。