Next.jsでLINEログインを実装する
はじめに
Next.jsでLINEログインを実装したので記事を投稿します。ウェブアプリ向けのLINEログインの処理はOAuth2.0の認可コードフローとOpenID Connectプロトコルに基づいています。本記事ではアクセストークンの取得と、アクセストークンを使ったプロフィール情報の取得までを記載します。
関連する筆者の記事
筆者がGoogleAPIのOAuth2.0認可を実装した際の記事を公開しています。本記事と同じ構成で記載されていますので、GoogleAPIのOAuth2.0認可の実装とLINEログインの実装を比較して読むことができます。是非参考にしてください。
参考資料
本記事に関連するLINEのドキュメントは以下です。
1. LINE DevelopersコンソールでLINEログインのチャネルを設定する
1.1. LINE Developersコンソールで新規プロバイダーを作成する
まずはLINE Developersコンソールでプロバイダーを作成します。プロバイダーとは、アプリを提供する個人または組織を表す概念です。
ここではzozooizozzoizioiiiooiという名前でプロバイダーを作成しています。

1.2. プロバイダーにLINEログインの新規チャネルを作成する
次に、プロバイダーにLINEログインの新規チャネルを作成します。
プロバイダー画面で新規チャネルを作成をクリックし、チャネルの種類でLINEログインを選択します。

サービスを提供する地域と会社自事業者の所在国・地域の選択、チャネル名とチャネル説明の入力などを行いチャネルを作成します。

LINE開発者契約に同意して作成ボタンをクリックすると、チャネルが作成されます。
1.3. チャネルのLINEログイン設定にコールバックURLを設定する
次に、チャネルのLINEログイン設定にコールバックURLを設定します。
コールバックURLはhttp://localhost:3000/api/line-login-callbackとしています。後ほどコールバックURLに指定した/api/line-login-callbackをNext.jsでAPIとして実装します。

1.4. チャネルIDとチャネルシークレットを確認する
これで、チャネルの設定は完了です。チャネルの基本設定からクライアントIDに当たるチャネルIDと、クライアントシークレットに当たるチャネルシークレットを確認することができます。これらの値はLINEログインの実装で必要になります。

2. Next.jsでLINEログインを実装する
ここからはNext.jsでLINEログインを実装していきます。参考に今回実装するLINEログインの処理の流れをシーケンス図として載せておきます。この段階でシーケンス図を見て処理のイメージが湧かない方でも、実装と動作確認後に再びシーケンス図を眺めてみると、イメージが湧いてくるのではないかと思います。
2.1. Next.JSアプリを新規作成する
まずは、以下のコマンドを実行してNext.jsアプリを新規作成します。
npx create-next-app@latest
コマンドを実行するとプロジェクト名を尋ねられます。あとはNext.jsのデフォルトを使うようにしました。必要に応じて設定を変更してください。
√ What is your project named? ... equals
√ Would you like to use the recommended Next.js defaults? » Yes, use recommended defaults
以下のコマンドを実行することで、ローカル開発サーバーを起動することができます。
npm run dev
ブラウザを開き、http://localhost:3000 を指定すると、ローカル開発サーバにアクセスすることができます。

2.2. LINEログインを実装する
Next.jsのRouteHandlersの仕組みを使って、2つのAPIを実装します。チャネルIDとチャネルシークレットには1.4. チャネルIDとチャネルシークレットを確認するで確認した値を指定してください。
2.2.1. LINEプラットフォームへリダイレクトするためのAPIを実装する
まずは自身のアプリからLINEプラットフォームへリダイレクトするためのAPIを実装します。
これらの処理をAPIとして実装して、バックエンドで処理を行うことで、チャネルIDを安全に保存することができます。
import { NextResponse } from "next/server";
import { randomBytes } from "crypto";
export async function GET() {
const state = randomBytes(32).toString("hex");
const authorizationUrl = new URL(
"https://access.line.me/oauth2/v2.1/authorize"
);
authorizationUrl.searchParams.set("response_type", "code");
authorizationUrl.searchParams.set("client_id", "チャネルID");
authorizationUrl.searchParams.set(
"redirect_uri",
"http://localhost:3000/api/line-login-callback"
);
authorizationUrl.searchParams.set("state", state);
authorizationUrl.searchParams.set("scope", "profile openid");
const response = NextResponse.redirect(authorizationUrl);
// 検証のためにstateをCookieに保存しておく
response.cookies.set("oauth_state", state, {
httpOnly: true,
secure: true,
sameSite: "lax",
maxAge: 600,
path: "/",
});
return response;
}
authorizationUrlがアプリからリダイレクトするLINEプラットフォームのURLです。
http://localhost:3000/api/line-login-callbackがLINEプラットフォームでの認可後にリダイレクトされるアプリのURLです。1.3. チャネルのLINEログイン設定にコールバックURLを設定するで指定したリダイレクトURLと一致させる必要があります。
2.2.2. LINEプラットフォームからリダイレクトを受けるためのAPIを実装する
次に、LINEプラットフォームからリダイレクトを受けるためのAPIを実装します。ここでは、stateの検証と、リダイレクト時にクエリパラメータとして付加された認証コードを使ったアクセストークンの取得と、取得したアクセストークンを使ったプロフィール情報を取得をしています。
import { NextRequest, NextResponse } from "next/server";
import { URL } from "url";
export async function GET(request: NextRequest) {
const url = new URL(request.url);
// Cookieに保存した値を使ってstateの検証を行う
const storedState = (await cookies()).get("oauth_state")?.value;
const receivedState = url.searchParams.get("state");
if (!receivedState || receivedState !== storedState) {
return NextResponse.redirect(
new URL("/?error=state_mismatch", request.url)
);
}
const code = url.searchParams.get("code");
if (!code) {
return NextResponse.redirect(new URL("/?error=missing_code", request.url));
}
try {
// アクセストークンの取得
const tokenResponse = await fetch("https://api.line.me/oauth2/v2.1/token", {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({
grant_type: "authorization_code",
code: code,
redirect_uri: "http://localhost:3000/api/line-login-callback",
client_id: "チャネルID",
client_secret: "チャネルシークレット",
}),
});
if (!tokenResponse.ok) {
return NextResponse.redirect(
new URL("/?error=token_request_failed", request.url)
);
}
const tokenJson = await tokenResponse.json();
const accessToken = tokenJson.access_token;
// プロフィール情報の取得
const profileResponse = await fetch("https://api.line.me/v2/profile", {
method: "GET",
headers: { Authorization: `Bearer ${accessToken}` },
});
if (!profileResponse.ok) {
return NextResponse.redirect(
new URL("/?error=profile_request_failed", request.url)
);
}
const profileJson = await profileResponse.json();
console.log(`profile: ${JSON.stringify(profileJson, null, 2)}`);
} catch (error) {
return NextResponse.redirect(
new URL("/?error=internal_server_error", request.url)
);
}
return NextResponse.redirect(new URL("/", request.url));
}
本来は、ここで取得したアクセストークンやプロフィール情報を使って機能を実現します。こちらの実装ではプロフィール情報をコンソールログに出力して、アプリのトップページである/にリダイレクトしています。
2.3. LINEログインのトリガとなるボタンを実装する
最後に、LINEログインのトリガとなるボタンを実装します。Next.jsアプリを新規作成した際に取得されたapp/page.tsの実装を以下の実装に置き換えます。ここではLINEプラットフォームへリダイレクトするするためのAPIである/api/line-loginへのリンクを「Log in」ボタンとして中央に表示するUIを実装しています。
ボタンのデザインはLINEログインボタン デザインガイドラインに従いましょう。
export default function Home() {
return (
<main className="flex min-h-screen flex-col items-center justify-center">
<a
href="/api/line-login"
aria-label="LINE Login"
className="w-[151px] h-11 bg-[url('/btn_login_base.png')] hover:bg-[url('/btn_login_hover.png')] active:bg-[url('/btn_login_press.png')]"
/>
</main>
);
}
3. ローカル開発サーバーを起動して動作を確認する
ローカル開発サーバーを起動して、動作を確認していきましょう。
3.1. ローカル開発サーバーを起動する
以下のコマンドを実行することで、ローカル開発サーバーを起動します。
npm run dev
ブラウザを開き、http://localhost:3000 を指定すると、ローカル開発サーバにアクセスし、「Log in」ボタンが表示されます。

3.2. LINEログインする
「Log in」ボタンをクリックすると、LINEプラットフォームにリダイレクトされます。

3.3. バックエンドのコンソールログにプロフィール情報が出力される
LINEログインが完了すると、LINEプラットフォームからアプリのトップページへリダイレクトされ、再び「Log in」ボタンが表示されます。
この時、npm run devを実行したコンソールにコンソールログとしてプロフィール情報が表示されれば正しく動作しています。
プロフィール情報の取得処理はバックエンドで処理を行っているため、フロントエンドであるブラウザのコンソールログには結果が出力されないことに注意してください。
おわりに
記事を読んでいただいてありがとうございました。今回はNext.jsでLINEログインを実装しました。LINEログインの実装の具体例として、どなたかの参考になれば嬉しいです。
Discussion