LINEログインのOIDC認可コードフローをSDKを使わず手元から試してみた

LINEログインのOIDC認可コードフローをSDKを使わず手元から試してみた

SDKやライブラリを使わず、curlとブラウザだけでLINEログインのOIDC認可コードフローを一から手で動かしてみました。各ステップでどんなリクエストが飛んで何が返ってくるのかを、実物で確認していきます。
2026.06.28

リテールアプリ共創部のるおんです。

普段LINEログインを使った認証機能では、SDKやライブラリに任せて「パラメータを設定したら動いた」で済ませていましたが、今回は、SDKや公式ライブラリをあえて使わずcurl とブラウザだけで LINEログインの OIDC(OpenID Connect)の認可コードフロー を一から自分で組み立てて動かしてみました。各ステップでどんなリクエストが飛んで、何が返ってくるのかを、実物で確認していきます。

個人的には、この 一連の流れを自分で実行してみる と、OAuth/OIDC の登場人物とやりとりが一気に腑に落ちる ので、普段ライブラリ任せで使っている方にこそおすすめです。

先に結論

今回やったこと(curl とブラウザで LINEログインの OIDC 認可コードフローをひと通り動かす)を、先に流れだけまとめます。

  • ブラウザで 認可リクエスト を送り、ログイン・同意して 認可コード(code) を受け取る
  • その code を curlトークンエンドポイント に送り、アクセストークンIDトークン を受け取る
  • IDトークンを デコード して、中に「誰がログインしたか(sub)」などの情報が入っていることを確認する
  • 受け取った IDトークンが 正しいもの(確かに LINE が発行した、改ざんされていないもの)か 、LINE の 検証エンドポイント で検証する
  • 最後に、アクセストークン を使って UserInfo エンドポイント を叩き、プロフィールを取得する(任意)

本来ならこれをアプリケーションでSDK等を用いて実装して動かしますが、今回は手元のブラウザとターミナルのcurlから試します。IDトークンで「誰がログインしたか」を受け取る(OIDCによる認証)だけでなく、受け取った アクセストークンAuthorization: Bearer ヘッダーに載せて UserInfo エンドポイント を叩き、表示名やアイコンなどのプロフィールも取得するところまでやってみます。

準備

  • LINE Developers アカウントLINE Developersコンソール
  • curl(ターミナル)
  • python3(IDトークンのデコードに使用。Mac なら標準で入っています)

OIDC のエンドポイントは、LINE が公開している OpenID Configuration で確認できます。最初に叩いておくと、以降で使う URL がすべて分かります。

curl https://access.line.me/.well-known/openid-configuration

返ってくる JSON のうち、今回使うのはこのあたりです。

フィールド 用途
authorization_endpoint https://access.line.me/oauth2/v2.1/authorize 認可リクエストの送り先(ブラウザ)
token_endpoint https://api.line.me/oauth2/v2.1/token code をトークンに交換(curl)
userinfo_endpoint https://api.line.me/oauth2/v2.1/userinfo プロフィール取得

1. LINEログインチャネル作成

https://developers.line.biz/console/

GoogleでいうOAuthクライアント登録にあたる作業です。LINEでは「LINEログインチャネル」を作ります。

  1. LINE Developersコンソールプロバイダー を作成(未作成の場合)
  2. プロバイダー内で 「新規チャネル作成」→「LINEログイン」 を選択して作成
  3. チャネル基本設定]タブで チャネルIDチャネルシークレット を控える
  4. LINEログイン設定]タブで コールバックURLhttp://localhost:8080/callback を登録

チャネルIDが OIDC の client_id、チャネルシークレットが client_secret にあたります。

スクリーンショット 2026-06-28 13.26.16

今回はローカルにサーバーを立てず、リダイレクト先のエラー画面の URL から code を手でコピーします。なので、コールバックURL は「動いていない」localhost で問題ありません。

2. 認可リクエスト(ブラウザ)で認可コードを受け取る

https://developers.line.biz/ja/docs/line-login/integrate-line-login/#making-an-authorization-request

まず、ログインを始めるための 認可リクエスト をブラウザから送ります。<チャネルID> を自分の値に置き換えて、次の URL を ブラウザのアドレスバーに貼る だけです。

認可リクエストのURL
https://access.line.me/oauth2/v2.1/authorize?response_type=code&client_id=<チャネルID>&redirect_uri=http://localhost:8080/callback&state=abc123&scope=openid%20profile&nonce=xyz789

クエリパラメータの意味はこうです。

パラメータ 意味
response_type code 認可コードがほしい、という宣言
client_id チャネルID どのアプリ(チャネル)からのリクエストか
redirect_uri コールバックURL 終わったらどこに戻すか(登録値と完全一致)
state abc123 CSRF対策。リクエストとコールバックの対応を確認する
scope openid profile 要求する権限(%20 はスペース)
nonce xyz789 リプレイ対策。あとで IDトークンの中に同じ値が入る

この URL をブラウザで開くと、LINE のログイン画面 → 同意画面(openid:内部識別子 / profile:プロフィール)が出ます。許可すると、LINE は ステータスコード302 で、登録したコールバックURLにリダイレクトしてきます。

スクリーンショット 2026-06-28 13.29.04

スクリーンショット 2026-06-28 13.30.01

http://localhost:8080/callback?code=(認可コード)&state=abc123

ローカルにサーバーがないので、ブラウザには「このサイトにアクセスできません」というエラー画面が出ますが問題ないです。大事なのは見た目ではなく、アドレスバーに入っている codestate です。

  • state が、先ほど送った abc123一致 しているか確認する(CSRF対策)
  • code の値をコピーしておく(次で使う)

ここまでが ブラウザ の担当です。ユーザーがログイン・同意する必要があるので、人間が操作するブラウザでやりとりし、その結果(認可コード)をブラウザ経由で受け取っています。

3. トークンリクエスト(curl)でトークンを受け取る

https://developers.line.biz/ja/docs/line-login/integrate-line-login/#get-access-token

受け取った code を、今度は トークンエンドポイント に送ってトークンに交換します。ここからは ブラウザではなく curl 、つまり「自分がアプリのサーバー役」になってリクエストを送ります。

<...> を自分の値に置き換えて実行します。

curl -s -X POST https://api.line.me/oauth2/v2.1/token \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -d 'grant_type=authorization_code' \
  -d 'code=<取得したcode>' \
  --data-urlencode 'redirect_uri=http://localhost:8080/callback' \
  -d 'client_id=<チャネルID>' \
  -d 'client_secret=<チャネルシークレット>'

成功すると、こんなレスポンスが返ってきます(値はダミー)。

トークンレスポンス
{
  "access_token": "(アクセストークン)",
  "token_type": "Bearer",
  "refresh_token": "(リフレッシュトークン)",
  "expires_in": 2592000,
  "scope": "profile openid",
  "id_token": "(IDトークン。JWT)"
}

アクセストークンは、このあとユーザー情報やその他のリソースにアクセスする際に、Bearer認証で毎回リクエストに含めて送信します。
一方のIDトークンは、「誰がログインしたか」をアプリに伝える 認証 のためのトークンです。アプリはこれを検証して、ログインしたユーザーを特定します。

4. IDトークンをデコードして中身を見る

レスポンスの id_token が、OIDC の主役です。形式は JWT で、ヘッダー.ペイロード.署名 の3つのパートを .(ドット)で繋いだ文字列になっています。

このうち ペイロード(2つ目) をデコードすると、中身が読めます。<id_token> を実際の値に置き換えて実行します。

echo '<id_token>' | cut -d '.' -f2 | python3 -c "import sys,base64,json;p=sys.stdin.read().strip();print(json.dumps(json.loads(base64.urlsafe_b64decode(p+'='*(-len(p)%4))),indent=2,ensure_ascii=False))"

デコードすると、こんな JSON が出てきます(sub などはマスクしています)。

IDトークンのペイロード
{
  "iss": "https://access.line.me",
  "sub": "U********************************",
  "aud": "<チャネルID>",
  "exp": 1782618947,
  "iat": 1782615347,
  "nonce": "xyz789",
  "amr": ["linesso"],
  "name": "(表示名)",
  "picture": "https://profile.line-scdn.net/..."
}

ここまで来ると、自分が送った値や設定が、そのまま IDトークンの中に入っている のが確認できます。

  • iss:発行者。https://access.line.me(=LINE)になっている
  • aud:このトークンの宛先。自分のチャネルID になっている(「このトークンは自分のアプリ向けか?」の確認に使う)
  • subユーザーの識別子 。アプリはこの値で「誰がログインしたか」を判断する
  • nonce:手順2で送った xyz789 がそのまま入っている(リプレイ対策が効いている)
  • amr:認証方法。linesso は「LINE のシングルサインオン(既にLINEにログイン済みでそのまま通った)」を表す

5. IDトークンを検証する(verifyエンドポイント)

https://developers.line.biz/ja/docs/line-login/verify-id-token/

さきほどのデコードは ただ中身を読んだだけ で、「そのトークンが本物か(確かに LINE が発行した、改ざんされていないものか)」は まだ確かめていません 。検証せずに sub を信用してしまうと、誰かが偽造したトークンを掴まされるおそれがあります。

検証は自前でもできますが、LINE には IDトークン検証用のエンドポイント/oauth2/v2.1/verify)が用意されています。今回はこれを使い、署名の検証まで含めて LINE 側にやってもらいます<...> を自分の値に置き換えて実行します。

curl -s -X POST https://api.line.me/oauth2/v2.1/verify \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -d 'id_token=<id_token>' \
  -d 'client_id=<チャネルID>' \
  -d 'nonce=xyz789'
パラメータ チェック内容
id_token IDトークン 署名・有効期限(exp)が正しいか(必須)
client_id チャネルID トークンの aud がこれと一致するか(必須)
nonce xyz789 トークンの nonce がこれと一致するか(任意)

検証に成功すると、IDトークンのペイロードがそのまま返ってきます 。「中身が読めた」ではなく、「署名・有効期限・audnonce のチェックを全部通った」という意味になります。

検証成功レスポンス(=正しいトークンだった)
{
  "iss": "https://access.line.me",
  "sub": "U********************************",
  "aud": "<チャネルID>",
  "exp": 1782618947,
  "iat": 1782615347,
  "nonce": "xyz789",
  "amr": ["linesso"],
  "name": "(表示名)",
  "picture": "https://profile.line-scdn.net/..."
}

逆に、トークンが壊れていたり、有効期限が切れていたり、audnonce が一致しないと、ペイロードではなくエラーが返ります

6. UserInfo でプロフィールを取る(任意)

「誰がログインしたか」は IDトークンの sub で分かります。表示名やアイコンなど、追加のプロフィール情報がほしいときは、アクセストークン を使って UserInfo エンドポイントを叩きます。

curl -s https://api.line.me/oauth2/v2.1/userinfo \
  -H 'Authorization: Bearer <access_token>'
UserInfoレスポンス
{
  "sub": "U********************************",
  "name": "(表示名)",
  "picture": "https://profile.line-scdn.net/..."
}

アクセストークンをBearerでヘッダーに載せて送信します。

おわりに

今回は、SDKを使わず curl とブラウザだけで、LINEログインの OIDC 認可コードフローをひと通り動かしてみました。やったことを振り返ると、流れはシンプルです。

  1. 認可リクエスト(ブラウザ)code を受け取る
  2. トークンリクエスト(curl)codeaccess_token / id_token に交換する
  3. IDトークンをデコード して「誰がログインしたか」を確認する
  4. IDトークンを検証(verifyエンドポイント)して、それが正しい(改ざんされていない)トークンか確かめる
  5. UserInfo でプロフィールを取る

普段 SDK 任せで使っていると、ログインボタンの裏でこのやりとりが走っていることはなかなか意識しません。ですが、一度 curl で通して動かしておくと、SDK が裏で何を肩代わりしてくれているのか がはっきり見えるようになります。LINEログインに限らず、OAuth/OIDC を「雰囲気で」使っている方の、最初の一歩になれば幸いです。

以上、どなたかの参考になれば幸いです。

参考

https://developers.line.biz/ja/docs/line-login/integrate-line-login/

https://developers.line.biz/ja/reference/line-login/

https://access.line.me/.well-known/openid-configuration

この記事をシェアする

関連記事