🐥

【Next.js,LINE】Next.jsでLINEログイン機能を実装する

2024/02/21に公開

はじめに

今回は、LINEログイン機能の実装をNextAuth.jsを用いた方法とLIFFを用いた方法の2パターンを、備忘録として書いていきます。
Next.jsのバージョンは14.1.0です。

(共通) 準備

Next.jsのプロジェクト作成

作成

任意のディレクトリで、以下のコマンドを用いて作成します。

npx create next-app@latest [プロジェクト名]

選択肢は全てデフォルトにしておきます。以下の画像のようになればok。

globals.cssの編集

app/globals.cssのファイルの中身を以下のように編集します。

globals.css
@tailwind base;
@tailwind components;
@tailwind utilities;

page.tsxの編集

app/page.tsxのファイルの中身を以下のように編集しておきます。

page.tsx
export default function Home() {
  return ( 
    <div>
      <h1>Home</h1>
    </div>
  );
}

LINE Developersサイトからチャネル作成

こちらを参考にして、作成してください。

準備が終わったので、次からNextAuth.jsを用いた方法とLIFFを用いた方法の2パターンを書いていきます。

NextAuth.jsを用いた方法

準備

(共通)準備を参考に、必要な準備をしてください。

NextAuth.jsをインストール

まず、Next.Auth.jsをインストールします。
ターミナルで以下のコマンドを実行します。

npm add next-auth

.envファイルを作成

ルートディレクトリに.envファイルを作成し、以下のように編集します。

.env
LINE_CLIENT_ID=作成したチャネルのチャネルID
LINE_CLIENT_SECRET=作成したチャネルのチャネルシークレット
NEXTAUTH_SECRET=以下のようにして作成

NEXTAUTH_SECRETには、以下のコマンドをターミナルで実行して得られた文字列を設定します。

openssl rand -base64 32

app/components/buttons.tsxを作成

ログイン用のボタンとログアウト用のボタンを作成します。
appディレクトリの配下にcomponentsフォルダを作成し、その直下にbuttons.tsxファイルを作成します。
以下のようにファイルの中身を記述します。

buttons.tsx
"use client";

import { signIn, signOut } from "next-auth/react";

export const LoginButton = () => {
  return (
    <button
      className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"
      onClick={() => signIn('line', { callbackUrl: '/' })}
    >
      ログイン
    </button>
  );
};

export const LogoutButton = () => {
  return (
    <button
      className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"
      onClick={() => signOut()}
    >
      ログアウト
    </button>
  );
};

signIn()が認証をさせるためのメソッドで、signOut()は認証後のセッションを切るメソッドです。これらの処理は、クライアンコンポーネントである必要からuse clientと冒頭で宣言しています。

app/options.tsxを作成

LINEを利用した認証機能を持たせます。
appディレクトリ直下にoptions.tsファイルを作成し、以下のようにファイルの中身を記述します。

options.tsx
import { NextAuthOptions } from "next-auth";
import LineProvider from "next-auth/providers/line";

export const authOptions: NextAuthOptions = {
    debug: true,
    session: { strategy: "jwt" },
    providers: [
        LineProvider({
            clientId: process.env.LINE_CLIENT_ID!,
            clientSecret: process.env.LINE_CLIENT_SECRET!
        })
    ]
}

app/api/auth/[...nextauth]/route.tsを作成

NextAuth.jsを使用する際の決まり事のようなものですが、app/api/auth/[...nextauth]/route.tsを作成し、ファイルの中身を以下のように記述します。

route.ts
import { authOptions } from "@/app/options";
import NextAuth from "next-auth";

const handler = NextAuth(authOptions);

export { handler as GET, handler as POST }

app/page.tsxを編集

表示する画面を作成していきます。
appディレクトリ直下のpage.tsxを以下のように編集します。

page.tsx
import { getServerSession } from 'next-auth';
import { LogoutButton } from './components/buttons'
import { authOptions } from './options';
import { redirect } from 'next/navigation';

export default async function Home() {
  const session = await getServerSession(authOptions);
  if (!session) {
    redirect('/sign_in')
  }

  return (
    <main className="flex min-h-screen flex-col items-center justify-center">
      <div>Welcome: {session?.user?.name}</div>
      <LogoutButton/>
    </main>
  )
}

ここでは、ログイン状態のユーザーには、ユーザー名とログアウトボタンを表示し、未ログイン状態のユーザーには、singInページへ遷移させます。

app/signIn/page.tsxを作成

ユーザーがログインするためのページを作成します。
appディレクトリ配下にsignInフォルダを作成し、その直下にpage.tsxファイルを作成します。page.tsxファイルの中身を以下のように記述します。

page.tsx
import { LoginButton } from '../components/buttons'

export default async function Home() {
  return (
    <main className="flex min-h-screen flex-col items-center justify-center">
      <LoginButton/>
    </main>
  )
}

ここでは、LoginButtonコンポーネントを呼び出して、ユーザーにログインボタンを提示します。

LIFFを用いた方法

ここでは、クライアント側でログインし、プロフィールを取得します。
サーバーサイドで、ユーザー情報を扱いたい場合はこちら(準備中なので、コメントで急かしてください)を参照してください。

LINE DevelopersサイトからLIFFアプリを追加

こちらを参考に、(共通)で作成したチャネルにて、LIFFアプリを追加してください。
エンドポイントURLは、LINEログイン完了後に遷移する先です。
LIFFアプリ作成時はhttps://localhostとでも設定しておきましょう。
また後ほど設定します。
LIFF IDを使用するので、メモしておきましょう。

参考画像

準備

(共通)準備を参考に、必要な準備をしてください。

LINE Front-end Framework(LIFF)のSDKをインストール

まず、LINE Front-end Framework(LIFF)のSDKをインストールします。
ターミナルで以下のコマンドを実行します。

npm install @line/liff

.envファイルを作成

ルートディレクトリに.envファイルを作成し、以下のように編集します。

.env
NEXT_PUBLIC_LIFF_ID=LIFF アプリを作成して取得したLIFF ID
NEXTAUTH_SECRET=以下のようにして作成

NEXTAUTH_SECRETには、以下のコマンドをターミナルで実行して得られた文字列を設定します。

openssl rand -base64 32

NEXT_PUBLIC_LIFF_IDはクライアント側で呼び出すので、NEXT_PUBLIC_が必要です。

app/page.tsxの編集

appディレクトリ直下のpage.tsxファイルを以下のように編集します。

page.tsx
"use client";

import liff from "@line/liff";
import React, { useState, useEffect } from "react";

export default function Home() {
  const [idToken, setIdToken] = useState<string | null>(null);
  const [displayName, setDisplayName] = useState<string | null>(null);

  useEffect(() => {
    liff
      .init({ liffId: process.env.NEXT_PUBLIC_LIFF_ID as string })
      .then(() => {
        console.log("LIFF init succeeded.");
        if (liff.isLoggedIn()) {
          const token = liff.getIDToken();
          setIdToken(token);
        } else {
          liff.login();
        }
      })
      .catch((e) => {
        console.error("LIFF init failed.", e);
        setIdToken('');
      });

    liff.ready.then(async () => {
      const userProfile = await liff.getProfile();
      console.log(userProfile);
      setDisplayName(userProfile.displayName);
    })
  }, []);

  if (idToken === null) {
    return <div>Loading...</div>;
  }
  return ( 
    <div>
      <h1>Hello {displayName}</h1>
    </div>
  );
}

以下の部分では、ユーザーが未ログイン状態のときにログインさせるようにしています。

        if (liff.isLoggedIn()) {
          const token = liff.getIDToken();
          setIdToken(token);
        } else {
          liff.login();
        }

以下の部分は、ログイン後に実行される処理です。
ここで、ユーザーのプロフィールを取得します。

    liff.ready.then(async () => {
      const userProfile = await liff.getProfile();
      console.log(userProfile);
      setDisplayName(userProfile.displayName);
    })

以下では、idTokenの値を元にローディング画面を表示させています。

  if (idToken === null) {
    return <div>Loading...</div>;
  }

以上で、実装自体はokです。
npm run devで立ち上げ、ngrok http 3000でngrokを発行してください。
ここhttps://localhostと設定したエンドポイントURLを発行したngrokに変更してください。
そして、発行したngrokにアクセスすると、ログインができます。

この先

liffを用いて、サーバーサイドでユーザー情報を扱う実装をする。
liffを使用して、ユーザーの課金管理を行う。
などをしていきます。

参考

https://zenn.dev/ufoo68/books/aa31a0a6fe0b53/viewer/implementapp
https://zenn.dev/hotter6163/articles/b7d2d3af91ef3a

Discussion