LINE 内ブラウザで OAuth 認証が動かない問題への対処

2026.02.02
Share:

はじめに

日本で Web サービスを提供するなら、LINE からのアクセスは無視できない。しかし LINE アプリ内ブラウザには厄介な問題がある。Google OAuth 認証が正常に動作しないことがあるのだ。

この問題に、2つのプロダクト開発で同時に遭遇した。同じ日に同じ問題を踏んだことで、汎用的な解決策を考えるきっかけになった。

問題の発見

2026年1月6日、Wakulier の開発日記にはこう書いた。

LINE内ブラウザ警告とOAuthエラーログの改善 LINEアプリ内ブラウザではGoogle OAuthが動作しないことがある。事前に警告を表示

同じ日、CancelNavi でも同様の対応をしていた。

アプリ内ブラウザでのログイン警告モーダルを追加 ユーザーが「ログインできない」と困惑するのを防ぎたい

LINE でサービスの URL をシェアすると、多くのユーザーは LINE アプリ内でそのままリンクを開く。そこで「Google でログイン」を押しても、認証フローが途中で止まったり、エラーになったりする。

ユーザーからすれば「なぜかログインできない」という体験になる。これは避けたい。

なぜ動かないのか

LINE 内ブラウザ(LINE IAB: In-App Browser)は、通常のブラウザとは異なる制約がある。

  1. サードパーティ Cookie の制限: OAuth のセッション管理に影響
  2. リダイレクト処理の違い: 認証後のコールバックが正しく処理されないことがある
  3. JavaScript API の制限: 一部の API が利用できない

Google OAuth に限らず、多くの OAuth 認証で同様の問題が発生する。

解決策: 事前警告 + 外部ブラウザ誘導

Claude Code と対処方針を検討し、「動かないものを動かす」のではなく、「動かない環境を避ける」アプローチを取った。

1. アプリ内ブラウザの検出

User-Agent に含まれる特徴的な文字列で検出する。

function isInAppBrowser(): boolean {
  const ua = navigator.userAgent || navigator.vendor;

  // LINE, Facebook, Instagram などの主要アプリ内ブラウザを検出
  const inAppPatterns = [
    /Line/i,      // LINE
    /FBAN/i,      // Facebook
    /FBAV/i,      // Facebook
    /Instagram/i, // Instagram
  ];

  return inAppPatterns.some(pattern => pattern.test(ua));
}

開発日記には「完璧な検出は難しいが、主要なアプリはカバー」と書いた。100% の精度は不要で、主要なケースをカバーできれば十分だ。

2. 警告バナーの表示(ランディングページ)

アプリ内ブラウザを検出したら、ページ上部に警告バナーを表示する。

{isInAppBrowser && (
  <div className="bg-yellow-500/10 border border-yellow-500/30 rounded-lg p-4">
    <p className="text-yellow-400 text-sm">
      LINE アプリ内で開いています。
      ログインには Safari や Chrome などの外部ブラウザをご利用ください。
    </p>
    <button onClick={openInExternalBrowser}>
      外部ブラウザで開く
    </button>
  </div>
)}

3. 外部ブラウザ誘導モーダル(ログイン画面)

ログインボタンを押すに、外部ブラウザで開くよう促すモーダルを表示する。

開発日記には UX の試行錯誤が記録されていた。

「ログインボタンを押す前」に警告するか、「押した後」に警告するか 最初はログインボタン押下後に表示していたが、クリック前に表示する方がスムーズと判断

押した後に警告すると、「なぜ動かないんだ」というフラストレーションが先に来る。事前に案内する方がユーザー体験として良い。

4. 外部ブラウザで開く

iOS と Android で挙動が異なるため、プラットフォームに応じた対応が必要になる。

function openInExternalBrowser(url: string) {
  // iOS Safari で開く
  if (/iPhone|iPad|iPod/.test(navigator.userAgent)) {
    // x-safari-https:// スキームは廃止されているため
    // URL をコピーして手動で開くよう案内するのが確実
    copyToClipboard(url);
    showToast("URL をコピーしました。Safari で開いてください。");
    return;
  }

  // Android は intent:// スキームで外部ブラウザを開ける場合がある
  // ただし LINE の仕様変更で動作しないケースもある
  window.location.href = url;
}

完璧な自動遷移は難しい。Claude Code で複数パターンを試した結果、「URL をコピーして、Safari/Chrome で開いてください」という案内が最も確実だった。

学んだこと

1. アプリ内ブラウザは「敵」ではない

LINE からのアクセスを敵視するのではなく、その環境での最適な体験を提供する姿勢が大切だ。

2. User-Agent 検出は「完璧」ではないが「実用的」

開発日記にも書いたが、100% の精度は不要。主要なケースをカバーできれば、大多数のユーザーを救える。

3. 事前告知が最善

問題が起きてから対処するより、問題が起きる前に案内する方がユーザー体験として優れている。

まとめ

LINE 内ブラウザで OAuth が動かない問題は、日本の Web サービス開発では避けて通れない。

対処の基本方針は以下の通り。

  1. User-Agent で検出: 主要なアプリ内ブラウザをカバー
  2. 事前に警告: ログイン前に外部ブラウザ誘導
  3. URL コピー機能: 確実に外部ブラウザで開けるよう案内

「動かないものを無理に動かす」のではなく、「動く環境に誘導する」というアプローチが現実的だ。


関連記事

Zeronova avatar

Zeronovaゼロノバ

Product Manager / AI-Native Builder

Web/IT業界19年以上・20以上のWebサービスを担当したPdM。東証プライム上場企業の子会社代表として事業経営を経験。現在はAIを駆使して企画から実装まで完結させる個人開発を実践中。

関連プロダクト

Wakulier(ワクリア)

継続案件の依頼管理ツール

CancelNavi(キャンセルナビ)

サブスク解約の最短ルート