LINEログインを実装中に Invalid redirect_uri が出たら、LINE Developersコンソールに登録したコールバックURLと、実際にリクエストで送っているURLが1文字も違わず一致していないのが原因です。この記事では、エラーの仕組みから設定手順・よくある落とし穴まで、コード例つきで順番に解説します。
仕組みの全体像(図解)
flowchart TD
A[ユーザーがLINEログインボタンをクリック] --> B[アプリがLINE認証URLを生成]
B --> C[redirect_uriをURLパラメータに含める]
C --> D{LINEサーバーが照合}
D -- 登録済みURLと一致 --> E[認証画面を表示]
D -- 不一致 --> F[Invalid redirect_uri エラー]
E --> G[ユーザーが許可]
G --> H[codeをredirect_uriに返す]
H --> I[アプリサーバーがcodeを受け取る]
I --> J[アクセストークンを取得]
J --> K[ユーザー情報を取得してログイン完了]
前提:このエラーが起きる理由
LINE Loginの認証フロー(OAuth 2.0)では、アプリが認証URLを組み立てるときに redirect_uri パラメータを含めます。LINEサーバーはそのURLを、LINE Developersコンソールの「コールバックURL」欄に登録されているURLと完全一致で比較します。
https://access.line.me/oauth2/v2.1/authorize
?response_type=code
&client_id=YOUR_CHANNEL_ID
&redirect_uri=https%3A%2F%2Fexample.com%2Fcallback ← ここが一致しないとエラー
&state=RANDOM_STRING
&scope=profile%20openid
「ほぼ同じ」では通りません。末尾スラッシュ1つ、http と https の違い、ポート番号の有無——すべてが不一致の原因になります。
手順1:LINE Developersコンソールでコールバックを確認する
- LINE Developers にログインします。
- 左メニューから Providers(プロバイダー) → 対象の Channel(チャネル) を選択します。
- タブから LINE Login を選び、「コールバックURL」 欄を開きます。
- 登録されているURLを正確にメモします(コピー推奨)。
注意: 「LINE Login」チャネルと「Messaging API」チャネルは別物です。LINEログインの設定は必ず「LINE Login」タイプのチャネルで行ってください。
手順2:コードで使っている redirect_uri を確認する
アプリ内で認証URLを組み立てている箇所を探します。
Python(Flaskの例)
import os
from urllib.parse import urlencode
LINE_CHANNEL_ID = os.environ["LINE_CHANNEL_ID"]
REDIRECT_URI = os.environ["LINE_REDIRECT_URI"] # 環境変数から取得する
def build_line_auth_url(state: str) -> str:
params = {
"response_type": "code",
"client_id": LINE_CHANNEL_ID,
"redirect_uri": REDIRECT_URI,
"state": state,
"scope": "profile openid",
}
return "https://access.line.me/oauth2/v2.1/authorize?" + urlencode(params)
Node.js(Expressの例)
const REDIRECT_URI = process.env.LINE_REDIRECT_URI;
function buildLineAuthUrl(state) {
const params = new URLSearchParams({
response_type: "code",
client_id: process.env.LINE_CHANNEL_ID,
redirect_uri: REDIRECT_URI,
state: state,
scope: "profile openid",
});
return `https://access.line.me/oauth2/v2.1/authorize?${params}`;
}
PHP(シンプルな例)
$redirectUri = getenv('LINE_REDIRECT_URI');
$params = http_build_query([
'response_type' => 'code',
'client_id' => getenv('LINE_CHANNEL_ID'),
'redirect_uri' => $redirectUri,
'state' => bin2hex(random_bytes(16)),
'scope' => 'profile openid',
]);
$authUrl = 'https://access.line.me/oauth2/v2.1/authorize?' . $params;
コードで組み立てた redirect_uri の値と、コンソールに登録したURLを並べて目視比較してください。
手順3:コンソールに正しいURLを登録する
- コンソールの「コールバックURL」欄の 「編集」 をクリックします。
- 実際にアプリが送るURLを そのまま 入力します。
- 「更新」 を押して保存します。
複数の環境(ローカル・ステージング・本番)を使う場合は、複数行に分けて登録できます。
# 登録例(1行ずつ入力)
http://localhost:3000/callback
https://staging.example.com/callback
https://example.com/callback
ローカル開発でlocalhostは使える? はい。LINE Developersはhttp://localhost始まりのURLを登録できます。http://localhost:3000/callbackのようにポート番号込みで登録しましょう。127.0.0.1とlocalhostは別URLとして扱われるので注意。
手順4:トークン取得時も同じ redirect_uri を使う
認証コード(code)を受け取った後、アクセストークンを取得するAPIにも redirect_uri を送る必要があります。この値も認証URLで使ったものと完全一致させてください。
Python(トークン取得)
import requests
def get_access_token(code: str) -> dict:
response = requests.post(
"https://api.line.me/oauth2/v2.1/token",
data={
"grant_type": "authorization_code",
"code": code,
"redirect_uri": REDIRECT_URI, # ← 認証URLで使った値と同じ
"client_id": LINE_CHANNEL_ID,
"client_secret": os.environ["LINE_CHANNEL_SECRET"],
},
headers={"Content-Type": "application/x-www-form-urlencoded"},
)
response.raise_for_status()
return response.json()
Node.js(トークン取得)
async function getAccessToken(code) {
const params = new URLSearchParams({
grant_type: "authorization_code",
code: code,
redirect_uri: REDIRECT_URI, // ← 認証URLで使った値と同じ
client_id: process.env.LINE_CHANNEL_ID,
client_secret: process.env.LINE_CHANNEL_SECRET,
});
const res = await fetch("https://api.line.me/oauth2/v2.1/token", {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: params,
});
if (!res.ok) throw new Error(await res.text());
return res.json();
}
よくあるエラーと対処
エラー1:末尾スラッシュの不一致
症状: コンソールに https://example.com/callback と登録しているのに、コードが https://example.com/callback/ を送っている(または逆)。
対処: コンソールとコードのどちらかに揃えます。どちらが正しいかではなく、一致しているかどうかが全てです。
# NGの例(末尾スラッシュが違う)
コンソール: https://example.com/callback
コード送信: https://example.com/callback/
# OKの例(一致)
コンソール: https://example.com/callback
コード送信: https://example.com/callback
エラー2:HTTP と HTTPS の混在
症状: ローカルは http:// で開発していたのに、本番URLを https:// で登録し忘れた(または逆)。
対処: 環境ごとに使うURLを .env ファイルで管理し、デプロイ時に差し替えます。
# .env.local
LINE_REDIRECT_URI=http://localhost:3000/callback
# .env.production
LINE_REDIRECT_URI=https://example.com/callback
エラー3:ポート番号の有無
症状: ローカルで http://localhost:3000/callback を使っているのに、コンソールに http://localhost/callback(ポートなし)しか登録していない。
対処: ポート番号付きで登録します。
# コンソールに追加登録する
http://localhost:3000/callback
エラー4:URLエンコードの二重適用
症状: redirect_uri を手動で %2F などにエンコードしてから、さらに urlencode に通している。
対処: エンコードは urlencode / URLSearchParams などのライブラリに任せ、生のURLを渡すだけにします。
# NG:自分でエンコードしてからさらにurlencode
redirect_uri = "https%3A%2F%2Fexample.com%2Fcallback" # 手動エンコード済
params = urlencode({"redirect_uri": redirect_uri}) # 二重エンコードになる
# OK:生のURLをそのまま渡す
redirect_uri = "https://example.com/callback"
params = urlencode({"redirect_uri": redirect_uri}) # ライブラリが適切にエンコード
エラー5:チャネルIDとコールバックURLの組み合わせ違い
症状: 複数のLINEチャネルを持っていて、チャネルAのIDでチャネルBのコールバックURLを使っている。
対処: チャネルID(client_id)と、そのチャネルのコンソールに登録したURLがセットで一致しているかを確認します。
# それぞれのチャネルでIDとコールバックURLを確認する
チャネルA: channel_id=1234567890 → callback=https://app-a.example.com/callback
チャネルB: channel_id=0987654321 → callback=https://app-b.example.com/callback
エラー6:コンソールの保存忘れ
症状: コンソールでURLを入力したが「更新」ボタンを押さずにページを離れた。
対処: 設定変更後は必ず 「更新」 ボタンをクリックし、ページを再読み込みして保存内容を目視確認します。コンソールの変更反映には数秒〜数十秒かかる場合があります。
確認チェックリスト
設定後、以下を上から順に確認してください。
- [ ] コンソールの「コールバックURL」欄に正しいURLが登録されている
- [ ] コード内の
redirect_uriとコンソールのURLが1文字単位で一致している - [ ] スキーム(
http/https)が一致している - [ ] ポート番号の有無が一致している
- [ ] 末尾スラッシュの有無が一致している
- [ ] URLを手動エンコードしていない(ライブラリに任せている)
- [ ] トークン取得時の
redirect_uriも認証時と同じ値を使っている - [ ] 複数チャネルがある場合、
client_idとredirect_uriが同じチャネルのものになっている
まとめ(次の一歩)
Invalid redirect_uri エラーの原因は、ほぼ確実に「コンソール登録値とコード送信値の不一致」です。エラーに直面したら「どこかが1文字違う」という前提で、コンソールとコードを並べて比較するのが最短の解決策です。
次の一歩として試すこと:
.envファイルでredirect_uriを一元管理し、ハードコードを排除する。- ステージング・本番で環境ごとの
.envを分け、デプロイ時の差し替えミスをなくす。 - LINE Loginの最新の仕様や制約は LINE Developersの公式ドキュメント で随時確認する。