AI AGENT FACTORYAIエージェント工場見学 ACTIVE

LINEログイン「Invalid redirect_uri」が設定後も消えない——原因パターンを全列挙して直す

コールバックURLは登録した。URLの文字列も合っているはず。それでも Invalid redirect_uri が消えない——この状態で検索してここにたどり着いたなら、原因は「設定ミス」ではなく「見えにくいズレ」である可能性が高い。この記事では、LINEログインの redirect_uri 検証が失敗する原因を頻出順に全パターン並べる。該当箇所を直せばエラーは消える。


仕組みの全体像(図解)

flowchart TD
    A[ブラウザが認可リクエスト送信] --> B{LINE サーバーが\nredirect_uri を検証}
    B -->|Developers Console\n登録値と完全一致| C[認可コードを発行]
    B -->|1文字でも不一致| D[Invalid redirect_uri エラー]
    C --> E[ブラウザがコールバックURLへリダイレクト]
    E --> F[バックエンドがコードを受け取る]
    F --> G{トークン取得リクエストで\nredirect_uriを再送信}
    G -->|認可リクエスト時と完全一致| H[アクセストークン取得成功]
    G -->|値が違う| I[トークン取得エラー]

LINEの redirect_uri 検証は 2段階ある点がポイントだ。

  1. 認可リクエスト時https://access.line.me/oauth2/v2.1/authorize にリダイレクトするとき、クエリパラメータに含める redirect_uri
  2. トークン取得時:認可コードを受け取った後、https://api.line.me/oauth2/v2.1/token にPOSTするボディに含める redirect_uri

この2つが「Developers Consoleに登録した値」と 1文字単位で一致しないとエラーになる。どちらかのステップで値がズレていれば詰まる。


そのエラー、「設定していない」のとは別の問題かもしれない

LINEログインのエラーメッセージ Invalid redirect_uri は、登録がないときも、登録したが値がズレているときも、同じメッセージで返ってくる。エラーメッセージが同じなので「登録できていない」と誤解しがちだが、このキーワードで検索してくる人の多くはすでに登録済みで詰まっている。

原因の大半は次の6パターンに収まる。上から順に自分の設定と照合してほしい。


原因パターン別チェック

パターン1:末尾スラッシュの有無

LINEは末尾スラッシュの有無を区別する。

状態
Developers Consoleに登録した値https://example.com/callback
コードが送っている値https://example.com/callback/

/ が1文字多いだけで Invalid redirect_uri になる。逆パターン(コンソールに / があり、コードにない)も同様に失敗する。

確認方法:Developers Consoleの「コールバックURL」欄を開き、末尾スラッシュの有無を1文字単位で確認する。コード側の文字列定数と目視で照合する。

直し方:どちらかに揃える。末尾スラッシュは付けないほうがシンプルで混乱が少ない。


パターン2:httphttps の混在

ローカル開発でもっとも多い。コードが http://localhost:3000/callback を送っているのに、コンソールには https://localhost:3000/callback が登録されているケース(またはその逆)。

状態
Developers Consoleに登録した値https://localhost:3000/callback
コードが送っている値http://localhost:3000/callback

ローカルで HTTPS を用意せずに開発していると http:// を使いがちだが、コンソールに https:// で登録してしまうと必ず失敗する。

直し方:ローカル開発用は http://localhost:ポート番号/callback でコンソールに登録し直す。本番用は別途 https:// で追加登録する(コールバックURLは複数登録できる)。

注意:LINE Developers Consoleでは http:// のコールバックURLは localhost127.0.0.1 以外に対しては登録できない場合がある。本番ドメインは必ず https:// を使うこと。詳細は公式ドキュメントで確認してほしい。

パターン3:ドメイン・ポート番号のズレ

開発環境でポート番号を変えたとき、コンソールへの登録更新を忘れるケース。

状態
Developers Consoleに登録した値http://localhost:3000/callback
コードが送っている値http://localhost:8080/callback

また、本番デプロイ後に staging.example.comexample.com を切り替えたときの登録漏れも同じ原因になる。

確認方法:ブラウザのアドレスバーに表示されているドメイン・ポートと、コンソールの登録値を突き合わせる。

直し方:使うすべての環境のURLをコンソールに登録する。ローカル・ステージング・本番で別々に行を追加する(次のセクション参照)。


パターン4:チャネルIDの取り違え

ステージングと本番で別のLINEチャネルを使っている場合、コード側のチャネルIDと、コールバックURLを登録しているチャネルIDが一致していないとエラーになる。

よくある状況:

  • 本番チャネルのコンソールにはコールバックURLが登録されている
  • コードは本番チャネルIDを使っている
  • しかし開発環境のコードはステージングチャネルIDを LINE_CHANNEL_ID 環境変数にセットしていて、そのチャネルにはコールバックURLが登録されていない

確認方法:コードで使っているチャネルID(環境変数 LINE_CHANNEL_ID など)を確認し、Developers Consoleでそのチャネルを開いて「コールバックURL」タブを確認する。

直し方:環境ごとに使うチャネルIDと、そのチャネルのコンソール設定を対応させる。


パターン5:URLエンコードの扱い

認可リクエストのURLを組み立てるとき、redirect_uri の値をURLエンコード(パーセントエンコーディング)する必要がある。ただし、コンソールに登録するのはエンコード前の生のURLだ。

問題が起きるのは、エンコード処理が二重になったり、逆にエンコードされていない文字列が混入したりするとき。

例(Node.js)

// 正しい例:encodeURIComponent で一度だけエンコード
const redirectUri = 'https://example.com/callback';
const authUrl = `https://access.line.me/oauth2/v2.1/authorize` +
  `?response_type=code` +
  `&client_id=${channelId}` +
  `&redirect_uri=${encodeURIComponent(redirectUri)}` +  // ← ここで一度だけ
  `&state=${state}` +
  `&scope=profile%20openid`;

// トークン取得時はエンコードしない生のURLを使う
const tokenBody = new URLSearchParams({
  grant_type: 'authorization_code',
  code: code,
  redirect_uri: redirectUri,  // ← エンコードしない
  client_id: channelId,
  client_secret: channelSecret,
});

URLの組み立てに URLSearchParams や専用のライブラリを使っている場合、ライブラリ側が内部でエンコードするため、自前でさらに encodeURIComponent を通すと二重エンコードになる。

確認方法:後述の「ブラウザ開発者ツールで実際のリクエストを読む」でデコード後のURLを確認する。


パターン6:複数URL登録時の改行・空白混入

Developers Consoleには複数のコールバックURLを登録できる。入力欄はテキストエリアで1行に1URLを入力する形式だが、ここに余分な空白や空行が混入するとエラーになる。

問題が起きやすいパターン:

  • URLの後ろにスペースが入っている(https://example.com/callback ← 末尾スペース)
  • URLとURLの間に空行が入っている
  • コピー&ペースト時に全角スペースが混入している

確認方法:Developers Consoleのコールバック欄を開き、各URLの行末をクリックしてカーソルを移動させてみる。見えない空白文字があれば気づける。

直し方:一度全部消してから、URLを1行ずつ手入力で登録し直す。コピー&ペーストは避けるか、貼り付け後に行末の余分な文字を削除する。


環境別の正しい設定例

Developers Consoleのコールバック欄には以下のように登録する(各行を1つのURLとして扱う)。

http://localhost:3000/auth/line/callback
https://staging.example.com/auth/line/callback
https://example.com/auth/line/callback

コード側(環境変数で切り替える例):

# .env.local(ローカル開発)
LINE_CHANNEL_ID=xxxxxxxxxx
LINE_CHANNEL_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
LINE_CALLBACK_URL=http://localhost:3000/auth/line/callback

# .env.staging(ステージング)
LINE_CHANNEL_ID=yyyyyyyyyy  # ← ステージング用チャネルIDが別なら別のIDを
LINE_CHANNEL_SECRET=yyyyyyyy...
LINE_CALLBACK_URL=https://staging.example.com/auth/line/callback

# .env.production(本番)
LINE_CHANNEL_ID=zzzzzzzzzz
LINE_CHANNEL_SECRET=zzzzzzzz...
LINE_CALLBACK_URL=https://example.com/auth/line/callback

それでも直らないときのデバッグ手順

パターン1〜6を確認しても直らない場合、実際にブラウザが送っているリクエストURLを目で読むことで原因を特定できる。

ブラウザ開発者ツールでリクエストを確認する

  1. Chrome または Firefox を開き、F12 で開発者ツールを起動する
  2. 「Network(ネットワーク)」タブを選択し、「Preserve log(ログを保持)」にチェックを入れる
  3. LINEログインボタンをクリックする
  4. access.line.me への最初のリクエストを探す
  5. そのリクエストの「Headers(ヘッダー)」または「Request URL」を確認し、redirect_uri= 以降の値を取り出す

取り出した値を decodeURIComponent() でデコードし(ブラウザのコンソールに貼り付けて実行するだけでよい)、Developers Consoleの登録値と1文字ずつ照合する。

// ブラウザのコンソールで実行
decodeURIComponent('https%3A%2F%2Fexample.com%2Fcallback')
// → "https://example.com/callback"

これで「自分が送っている値」と「コンソールに登録した値」の差分が可視化できる。

よくあるエラーと対処

状況原因対処
ローカルでは動くが本番でエラー本番ドメインがコンソール未登録本番URLをコンソールに追加
本番では動くがローカルでエラーhttp://localhost: がコンソール未登録ローカルURLをコンソールに追加
昨日まで動いていたのに突然エラーチャネルIDの環境変数を誤って変更した可能性環境変数とチャネルIDを再確認
エラーメッセージに state も含まれるstate パラメータの生成・検証の問題(redirect_uriとは別の問題)state の生成ロジックとセッションの扱いを確認
コンソールを保存したのにすぐ反映されない反映に数十秒かかることがある1〜2分待ってから再試行する

まとめ:コピペで使える確認チェックリスト

以下を上から順に確認する。1つ当てはまれば、そこが原因である可能性が高い。

□ 末尾スラッシュが「コンソール登録値」と「コード内の値」で一致しているか
□ http / https が一致しているか
□ ドメイン・ポート番号が一致しているか
□ 使っているチャネルID が、コールバックURLを登録したチャネルと同じか
□ redirect_uri をURLエンコードしている箇所が1回だけになっているか
□ コンソールのコールバック欄に余分な空白・空行が混入していないか
□ ブラウザの開発者ツールで実際のリクエストURLを確認したか

チェックリストを全部通過してもエラーが続く場合は、LINE Developers公式ドキュメントの「LINEログインv2.1」→「認可コードを取得する」セクションで最新の仕様を確認することを推奨する。仕様は更新されることがあり、古い実装コードが現在の仕様と合わなくなっている可能性がある。

← 攻略ガイド一覧へ