こんにちは。
最近、新規のWebアプリケーションで、ユーザーの利便性を最大限に高めるため、LINE LIFF(LINE Front-end Framework)を用いたシームレスな認証(LINEログイン) を実装しました。
LIFFを使うことで、ユーザーはLINEアプリ内からブラウザを開くことなく(または外部ブラウザからでもシームレスに)ログインでき、UXが劇的に向上します。しかし、Next.js(NextAuth.js)との連携や、ローカルでの開発環境構築、さらにはモバイルブラウザ特有のセッション管理において、いくつか乗り越えるべき壁がありました。
この記事では、LIFF + NextAuthを用いた認証基盤の構築と、安全かつ効率的なローカル開発環境の作り方についてご紹介します。
1. NextAuth.jsとLINE LIFFの統合(IDトークン検証)
LINEログインを実装する際、NextAuth.js(現在は Auth.js)の標準の LINEProvider を使う方法もありますが、LIFFを経由する場合は少しフローが異なります。
LIFF SDKをクライアント側で初期化(liff.init())し、成功するとユーザーの IDトークン が取得できます。このIDトークンをバックエンド(NextAuthのカスタムプロバイダー)に送信し、署名と有効性を検証してセッションを確立する、という流れになります。
実装のポイント
NextAuth側で CredentialsProvider を拡張し、LIFFから送られてきたIDトークンを検証する処理を追加します。
// pages/api/auth/[...nextauth].ts (一部抜粋)
import CredentialsProvider from "next-auth/providers/credentials";
export default NextAuth({
providers: [
CredentialsProvider({
id: "line-liff",
name: "LINE LIFF",
credentials: {
idToken: { label: "ID Token", type: "text" }
},
async authorize(credentials) {
if (!credentials?.idToken) return null;
// LINEのAPIエンドポイントでIDトークンを検証
const res = await fetch("https://api.line.me/oauth2/v2.1/verify", {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({
id_token: credentials.idToken,
client_id: process.env.LINE_CLIENT_ID!
})
});
const data = await res.json();
if (data.error) return null;
// DBにユーザーが存在しなければ作成し、ユーザーオブジェクトを返す
const user = await findOrCreateUserByLineId(data.sub, data.name, data.picture);
return user;
}
})
],
// ...
});
クライアント側からは、取得した idToken を signIn("line-liff", { idToken: liff.getIDToken() }) のように渡すだけで、NextAuthのセッション管理に載せることができます。
2. ngrokのDocker化によるローカル開発環境の最適化
LIFFアプリを開発するためには、LINE Developersコンソールに「エンドポイントURL」を登録する必要があります。このURLは HTTPSでなければならない(localhost は不可) ため、ローカル開発では ngrok などのトンネリングツールが必須です。
開発メンバー全員が手元のPCにngrokをインストールし、発行されたURLを毎回LINEのコンソールに登録し直すのは非常に手間です。そこで、ngrokをDocker Composeに組み込み、クロスオリジン(CORS)要件をクリアしつつ環境を統一しました。
# docker-compose.yml
version: '3.8'
services:
app:
build: .
ports:
- "3000:3000"
ngrok:
image: ngrok/ngrok:latest
ports:
- "4040:4040"
environment:
NGROK_AUTHTOKEN: ${NGROK_AUTHTOKEN}
command: "http app:3000"
depends_on:
- app
これにより、docker-compose up するだけで自動的にNext.jsアプリとngrokが立ち上がります。固定ドメイン(有料プラン)を割り当てておけば、開発時のエンドポイントURL登録作業すら不要になり、開発体験(DX)が飛躍的に向上します。
3. スマホブラウザとLINE内ブラウザのセッション管理
LIFF特有の落とし穴として、「外部ブラウザ(SafariやChrome)」と「LINE内ブラウザ」の挙動の違いがあります。
ログイン・ログアウトの不整合
LINE内ブラウザでは、LINEアプリのログイン状態をそのまま引き継ぐため自動ログインが容易です。しかし、外部ブラウザにリダイレクトされた場合、セッションが切れていたり、再度LINEのログイン画面(メールアドレス入力)を求められたりすることがあります。
解決策
LIFFの仕様に基づき、ブラウザのURLパラメータやリダイレクトのハンドリングを正確に行う必要があります。特にログアウト処理では、NextAuthの signOut() を呼ぶだけでなく、LIFF側でも liff.logout() を呼び出さないと、次回アクセス時に自動で以前のアカウントでログインされてしまう「セッション残り」が発生します。
const handleLogout = async () => {
// 1. LIFFからログアウト
if (liff.isLoggedIn()) {
liff.logout();
}
// 2. NextAuthのセッションを破棄
await signOut({ callbackUrl: '/login' });
};
まとめ
LINE LIFFとNextAuthの組み合わせは、強力なUXをもたらす一方で、インフラ(HTTPS必須)やセッション管理(ブラウザごとの挙動の違い)に関する特有の課題があります。
- NextAuthのCredentialsを拡張し、IDトークンで安全に認証する
- Docker化されたngrokを活用し、チーム全体でHTTPSのローカル開発環境を統一する
- LIFF側とNextAuth側、双方のセッションライフサイクルを意識してログアウト処理を実装する
これらのポイントを押さえることで、堅牢かつ開発しやすいLIFFアプリの基盤を構築できます。モバイル中心のサービス開発において、LINEログインは強力な武器になりますので、ぜひ参考にしてみてください!

![[Next.js] Page RouterからApp Routerへの乗り換え手順](/assets/ogp/nextjs-app-router-migration.webp)