🥯

Next.jsにClerkを設定する簡易手順

2023/08/05に公開

はじめに

  • Next.js のプロジェクトに Clerk を設定する手順を紹介します。
  • 作業コードは以下にあります。

https://github.com/hayato94087/nextjs-clerk-simple-sample

Clerkとは

  • Clerk とは、認証機能を提供するサービスです。
  • Clerk を利用することで、 Next.js で認証機能を簡単に実装できます。

https://www.youtube.com/watch?v=aQN4bJ1yc-k

以降では実際に、Next.js で Clerk を設定していきます。

Clerkのアカウント作成

Clerk のアカウントを作成します。Clerk へのログインは、GitHub アカウントで行えます。

サイトにアクセスします。

https://clerk.com/

「Sign in」をクリックします。

「Continue with GitHub」で自身の GitHub アカウントでログインします。

「Authorize clerk.inc」をクリックします。

このページまで来れば、Clerk のアカウント作成は完了です。

Clerkでアプリケーション作成

続いて、Clerk 上でアプリケーションを作成します。

  1. アプリケーション名を入力します。(今回は「nextjs-clerk-sample」と入力します)
  2. 認証方法を設定します。(今回は「Google」を選択します)
  3. 「Create Application」をクリックし、アプリケーションを作成します。

アプリケーションの作成が完了しました。

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

作業するプロジェクトを新規に作成していきます。

長いので、折りたたんでおきます。

新規プロジェクト作成と初期環境構築の手順詳細
$ pnpm create next-app@latest nextjs-clerk-simple-sample --typescript --eslint --import-alias "@/*" --src-dir --use-pnpm --tailwind --app
$ cd nextjs-clerk-simple-sample

以下の通り不要な設定を削除し、プロジェクトの初期環境を構築します。

$ mkdir src/styles
$ mv src/app/globals.css src/styles/globals.css
src/styles/globals.css
@tailwind base;
@tailwind components;
@tailwind utilities;
src/app/page.tsx
export default function Home() {
  return (
    <main className="text-lg">
      テストページ
    </main>
  )
}
src/app/layout.tsx
import '@/styles/globals.css'

export const metadata = {
  title: "Create Next App",
  description: "Generated by create next app",
};

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="ja">
      <body className="">{children}</body>
    </html>
  );
}
tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    "./src/components/**/*.{js,ts,jsx,tsx,mdx}",
    "./src/app/**/*.{js,ts,jsx,tsx,mdx}",
  ],
  plugins: [],
};
tsconfig.json
{
  "compilerOptions": {
    "target": "es5",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "incremental": true,
    "plugins": [
      {
        "name": "next"
      }
    ],
+   "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"],
    }
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
  "exclude": ["node_modules"]
}

コミットします。

$ pnpm build
$ git add .
$ git commit -m "新規にプロジェクトを作成し, 作業環境を構築"

Clerkをインストール

Next.js で Clerk が提供する SDK を利用するために、Clerk のパッケージをインストールします。

$ pnpm add @clerk/nextjs

環境変数を設定

環境変数を .env.local に設定します。APIKEY はダッシュボードから取得します。

APIKEY を .env.local に設定します。

$ touch .env.local
.env.local
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=your_publishable_key
CLERK_SECRET_KEY=your_secret_key

ClerkProviderの設定

どこからでもセッション、認証済みのユーザー情報などの認証情報にアクセスできるように、<ClerkProvider> コンポーネントを設定します。

layout.tsx<ClerkProvider> を設定します。

src/app/layout.tsx
+import { ClerkProvider } from "@clerk/nextjs";
import "./globals.css";

export const metadata = {
  title: "Create Next App",
  description: "Generated by create next app",
};

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
+   <ClerkProvider>
      <html lang="ja">
        <body className="bg-white">{children}</body>
      </html>
+   </ClerkProvider>
  );
}

アプリケーション全体を保護

middleware.ts でアプリケーションのどの部分を保護するか設定できます。

matcher で保護したいパスを指定します。今回はアプリケーション全体を保護します。

$ touch src/middleware.ts
src/middleware.ts
import { authMiddleware } from "@clerk/nextjs";

export default authMiddleware();

export const config = {
  matcher: ["/((?!.*\\..*|_next).*)", "/", "/(api|trpc)(.*)"],
};

動作確認

ローカルで実行します。

$ pnpm dev

ブラウザで http://localhost:3000/ にアクセスします。すると、想定どおり、ログインページにリダイレクトされました。Continue with Google をクリックすると、Google のログイン画面に遷移します。

Google アカウントにログインします。

ユーザー名を入力するとアカウントが作成されます。

ログインが完了して、ページが表示されます。

コミットします。

$ pnpm build
$ git add .
$ git commit -m "Clerkの設定を実施"

アカウント一覧を確認

Clerk のダッシュボードから、アカウント一覧を確認できます。

  1. Users をクリックします。
  2. ユーザー一覧に、先ほど Google 認証したユーザーが表示されます。

ソーシャルログインの追加

Clerk では以下のソーシャルログインが利用できます。日本でよく使われる LINE も含まれています。

  • Google
  • Facebook
  • Twitter
  • TikTok
  • Discord
  • Twitch
  • GitHub
  • GitLab
  • LinkedIn
  • HubSpot
  • Atlassian
  • Bitbucket
  • Dropbox
  • Microsoft
  • Notion
  • Apple
  • LINE
  • Coinbase
  • Spotify
  • Box
  • Xero
  • Slack
  • Linear

https://clerk.com/docs/authentication/overview

ソーシャルログインの追加は簡単にできます。

ダッシュボードのメニューからソーシャルログインを追加します。

  1. User & Authentication をクリック
  2. Social Connection をクリック
  3. 追加したいソーシャルログインをクリック

今回は facebook を追加します。

追加できました。

ログインページに facebook のボタンが追加されました。

Social Connection から facebook での認証は無効化しておきます。

ユーザボタンの追加

Clerk では、ユーザーのログイン状態に応じて、ユーザー名やログインボタンを表示できます。現時点では英語しか対応されていませんが、<UserButton /> を利用することで、簡単に実装できます。

以下を実装します。

  • middleware.ts を修正し、 http://localhost:3000/ に認証していなくてもアクセスできるようにする。
  • 認証されている場合は、認証されてたユーザーに合わせたユーザーボタンを表示、認証されていない場合は、ログインボタンを表示します。

まず、middleware.ts に認証していなくてもアクセスできるように publicRoutes を追加します。publicRoutes についてはこちらを参照ください。

src/middleware.ts
import { authMiddleware } from "@clerk/nextjs";

export default authMiddleware(
+ {
+   publicRoutes: ["/"],
+ }
);

export const config = {
  matcher: ["/((?!.*\\..*|_next).*)", "/", "/(api|trpc)(.*)"],
};

そして、pages.tsx を修正します。

  • <SignedIn /> は、認証されている場合に、children が表示されるコンポーネントです。
  • <UserButton /> は、認証されているユーザーに合わせたユーザーボタンを表示するコンポーネントです。
  • <SignedOut /> は、認証されていない場合に、children が表示されるコンポーネントです。
  • <SignInButton /> は、ログインボタンを表示するコンポーネントです。
src/app/pages.tsx
+import { SignInButton, SignedIn, SignedOut, UserButton } from "@clerk/nextjs";

export default function Home() {
  return (
+   <>
+     <header
+       style={{
+         display: "flex",
+         justifyContent: "space-between",
+         padding: 20,
+       }}
+     >
+       <h1>My App</h1>
+       <SignedIn>
+         {/* Mount the UserButton component */}
+         <UserButton afterSignOutUrl="/" />
+       </SignedIn>
+       <SignedOut>
+         {/* Signed out users get sign in button */}
+         <SignInButton />
+       </SignedOut>
+     </header>
      <main className="text-lg">テストページ</main>
+    </>
  );
}

それでは、実行してみます。

$ pnpm dev

http://localhost:3000/ にアクセスすると、ログインボタンが表示されます。ログインボタンをクリックすると、ログインページに遷移します。

ログインします。

ログイン後にユーザーボタンを表示されました。

クリックすると、ユーザー情報が表示されます。「Manage account」をクリックします。

アカウント管理画面がポップアウトされます。英語ですが、このページにはアカウント情報の詳細が表示されます。

「Sign out」をクリックするとログアウトします。

ログアウト後には、ログインボタンが表示されます。

コミットします。

$ pnpm build
$ git add .
$ git commit -m "ユーザーボタンを追加"

ユーザー情報の取得

currentUser() でユーザー情報の簡単に取得できます。取得できるユーザー情報は以下を参照ください。

項目 タイプ 説明ion
externalId string 外部システムで使用するユーザーのID。インスタンス全体で一意です。
emailAddress[] string ユーザーの電子メールアドレス。インスタンス全体で一意であす。最初の電子メールアドレスがユーザーのプライマリ電子メールアドレスとして設定されます。
phoneNumber[] string ユーザーの電話番号。インスタンス全体で一意です。最初の電話番号がユーザーのプライマリ電話番号として設定されます。
username string ユーザーが設定したユーザー名。インスタンス全体で一意です。
password string ユーザーに与える平文のパスワード。
firstName string ユーザーの名。
lastName string ユーザーの姓。
publicMetadata Record<string, unknown> ユーザーに保存されたメタデータで、フロントエンドとバックエンドの両方のAPIで表示されます。
privateMetadata Record<string, unknown> ユーザーに保存されたメタデータで、バックエンドAPIのみで表示されます。
unsafeMetadata Record<string, unknown> ユーザーに保存されたメタデータで、フロントエンドとバックエンドの両方のAPIで表示されます。

詳細は以下を参照ください。

https://clerk.com/docs/nextjs/user-object

ログインしている場合は、ユーザー情報を表示するようにします。

  • ログインしている場合は、名前を表示します。
  • ログインしている場合は、privateMeatadata を表示します。
src/app/pages.tsx
import {
  SignInButton,
  SignedIn,
  SignedOut,
  UserButton,
+  currentUser,
} from "@clerk/nextjs";

-export default function Home() {
+export default async function Home() {
+ const user = await currentUser();

  return (
    <>
      <header
        style={{
          display: "flex",
          justifyContent: "space-between",
          padding: 20,
        }}
      >
        <h1>My App</h1>
        <SignedIn>
          {/* Mount the UserButton component */}
          <UserButton afterSignOutUrl="/" />
        </SignedIn>
        <SignedOut>
          {/* Signed out users get sign in button */}
          <SignInButton />
        </SignedOut>
      </header>
      <main className="text-lg">
-       テストページ
+       <SignedIn><div>{user?.firstName}</div></SignedIn>
+       <SignedIn><div>{JSON.stringify(user?.privateMetadata)}</div></SignedIn>
      </main>
    </>
  );
}

privateMetadata とはユーザーが自由に設定できるメタデータです。privateMetadata は、ユーザーのプライバシーを保護するために、フロントエンドからはアクセスできません。バックエンドからはアクセスできます。

privateMetadata を設定します。まず Clerk の管理コンソールにアクセスします。ユーザー一覧からユーザーを選択します。

Metadata のセクションまでスクロールします。

「Edit」をクリックし、Private を編集することで、privateMetadata を設定できます。

ローカルサーバで動作確認をします。

$ pnpm dev

ログインすると、ユーザーの名前と先程設定した privateMetadata が表示されます。

コミットします。

$ pnpm build
$ git add .
$ git commit -m "currentUserを追加"

まとめ

  • Next.js のプロジェクトに Clerk を設定する手順を紹介しました。
  • 作業コードは以下にあります。

https://github.com/hayato94087/nextjs-clerk-simple-sample

Discussion