LINEログイン

1import { signInWithCustomToken, signOut } from 'firebase/auth';
2import { collection, doc, setDoc } from 'firebase/firestore';
3import { useRouter } from 'next/router';
4import React, { useEffect } from 'react';
5import { useAuth } from '../context/auth';
6import { auth, db } from '../firebase/client';
7import { Site } from '../lib/site';
8
9const AuthLine = () => {
10  const router = useRouter();
11  const { user } = useAuth();
12
13  const openLineLoginPage = async () => {
14    const stateRef = doc(collection(db, 'lineStates'));
15    const state = stateRef.id;
16
17    await setDoc(stateRef, {
18      createdAt: Date.now(),
19    });
20
21    const url = new URL('https://access.line.me/oauth2/v2.1/authorize');
22    url.search = new URLSearchParams({
23      response_type: 'code',
24      client_id: process.env.NEXT_PUBLIC_LINE_CLIENT_ID as string,
25      redirect_uri: `${Site.origin}/line-login`,
26      state,
27      scope: 'profile openid',
28    }).toString();
29
30    location.assign(url);
31  };
32
33  useEffect(() => {
34    if (router.query.code && router.query.state) {
35      fetch('/api/line-custom-token', {
36        method: 'POST',
37        headers: {
38          'Content-Type': 'application/json',
39        },
40        body: JSON.stringify({
41          code: router.query.code as string,
42          state: router.query.state as string,
43        }),
44      })
45        .then((res) => res.text())
46        .then((token) => {
47          signInWithCustomToken(auth, token).then(() => {
48            router.replace(
49              {
50                query: {
51                  id: router.query.id,
52                },
53              },
54              undefined,
55              {
56                shallow: true,
57              }
58            );
59          });
60        });
61    }
62  }, [router.query.code]);
63
64  return (
65    <div>
66      <button
67        className="bg-[#06c755] px-3 py-2 rounded shadow text-white"
68        onClick={openLineLoginPage}
69      >
70        LINE でログイン
71      </button>
72      {user && (
73        <div className="mt-4">
74          <p className="mb-2">ログイン中です</p>
75
76          <div className="flex items-center space-x-4">
77            <img
78              className="rounded-full w-10 h-10"
79              src={user.photoURL}
80              alt=""
81            />
82            <p>{user.name}</p>
83            <button className="text-pink-600" onClick={() => signOut(auth)}>
84              ログアウト
85            </button>
86          </div>
87        </div>
88      )}
89    </div>
90  );
91};
92
93export default AuthLine;

解説

全体の流れ

  1. チャネルを作成
  2. コールバックURLの設定(改行区切りで複数設定可能)
  3. LINEログイン画面へ遷移
  4. 認可コードの取得
  5. 認可コードを使ってアクセストークンを取得
  6. アクセストークンを使ってLINEユーザーID&ユーザー情報を取得
  7. ユーザーデータを使ってユーザーとカスタムトークンを作成
  8. カスタムトークンを使ってFirebaseにログイン

LINEからメールアドレスも取得したい場合メールアドレスの取得権限を申請し、リクエスト時のスコープ設定を profile openid email に設定してください。

使用ライブラリ

なし

参考サイト