Next.js×Supabase Authで認証機能を実装する

## はじめに
最近よく使われているSupabaseのAuthを使って認証機能を実装しました。

Supabaseは、オープンソースのFirebase代替プラットフォームで、リアルタイムデータベース、認証、ストレージなどの機能を提供します。

今回は、Next.jsとSupabase Authを使用して、ユーザー登録、ログイン、ログアウトなどの基本的な認証機能を実装する方法についてステップバイステップで紹介しています。

Supabaseで認証機能を実装する際は参考にしていただければと思います。

## Supabase Authとは
Supabase Authは、Supabaseが提供する認証およびユーザー管理のためのサービスです。

Supabase Authは、簡単かつセキュアなユーザー認証機能を提供し、開発者がアプリケーションに迅速に統合できるよう設計されています。

Supabase Authを使用することで、ユーザー登録やログイン機能、セッション管理などを実現することができます。

## Next.js×Supabase Authで認証機能を実装する

### 1. プロジェクトのセットアップ

まず、Next.jsのプロジェクトを作成します。次に、Supabaseのクライアントライブラリをインストールします。

```
npx create-next-app@latest supabase-auth-app --typescript
cd supabase-auth-app
npm install @supabase/supabase-js
```

### 2. Supabaseの設定

Supabaseプロジェクトを作成し、APIキーとURLを取得します。これらの情報は、Supabaseのダッシュボードで確認できます。

次に、環境変数を設定します。プロジェクトルートに.envファイルを作成し、以下のように設定します。

```.env
NEXT_PUBLIC_SUPABASE_URL=your-supabase-url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-supabase-anon-key
```


### 3. Supabaseクライアントの設定

lib/supabase.tsファイルを作成し、Supabaseクライアントを初期化します。

```lib/supabase.ts
import { createClient } from '@supabase/supabase-js';

const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!;
const supabaseKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!;
const supabase = createClient(supabaseUrl, supabaseKey);

export { supabase };
```

### 4. ユーザー登録とログインページの作成

pages/signup.tsxファイルを作成し、ユーザー登録ページを実装します。

```pages/signup.tsx
import { useState, FormEvent } from 'react';
import { supabase } from '../lib/supabase';

const SignUp = () => {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');

  const handleSignUp = async (e: FormEvent) => {
    e.preventDefault();
    const { user, error } = await supabase.auth.signUp({ email, password });
    if (error) {
      console.error(error.message);
    } else {
      console.log('User signed up:', user);
    }
  };

  return (
    <form onSubmit={handleSignUp}>
      <input
        type="email"
        placeholder="Email"
        value={email}
        onChange={(e) => setEmail(e.target.value)}
      />
      <input
        type="password"
        placeholder="Password"
        value={password}
        onChange={(e) => setPassword(e.target.value)}
      />
      <button type="submit">Sign Up</button>
    </form>
  );
};

export default SignUp;
```

全体像は上記のようになります。各コードを詳しく説明していきます。

```tsx
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
```
useStateを使用して、emailとpasswordの状態を管理します。初期値は空文字列です。

```tsx
const handleSignUp = async (e: FormEvent) => {
  e.preventDefault();
  const { user, error } = await supabase.auth.signUp({ email, password });
  if (error) {
    console.error(error.message);
  } else {
    console.log('User signed up:', user);
  }
};
```

handleSignUpというフォーム送信時に呼び出される非同期関数を定義します。

e.preventDefault()でフォーム送信時のデフォルト動作（ページのリロード）を防いでいます。

SupabaseのsignUpメソッドを使用して、ユーザーを登録します。このメソッドはemailとpasswordを引数に取ります。

ifのところは、エラーハンドリングをしており、エラーが発生した場合、コンソールにエラーメッセージを表示し、ユーザー登録が成功した場合、コンソールにユーザー情報を表示します。


```tsx
return (
  <form onSubmit={handleSignUp}>
    <input
      type="email"
      placeholder="Email"
      value={email}
      onChange={(e) => setEmail(e.target.value)}
    />
    <input
      type="password"
      placeholder="Password"
      value={password}
      onChange={(e) => setPassword(e.target.value)}
    />
    <button type="submit">Sign Up</button>
  </form>
);
```

フォームの送信イベントをhandleSignUp関数にバインドしています。

メールアドレスとパスワードはonChangeイベントでそれぞれのset関数をバインドします。

同様に、pages/login.tsxファイルを作成し、ログインページを実装します。

```pages/login.tsx
import { useState, FormEvent } from 'react';
import { supabase } from '../lib/supabase';

const Login = () => {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');

  const handleLogin = async (e: FormEvent) => {
    e.preventDefault();
    const { user, error } = await supabase.auth.signIn({ email, password });
    if (error) {
      console.error(error.message);
    } else {
      console.log('User logged in:', user);
    }
  };

  return (
    <form onSubmit={handleLogin}>
      <input
        type="email"
        placeholder="Email"
        value={email}
        onChange={(e) => setEmail(e.target.value)}
      />
      <input
        type="password"
        placeholder="Password"
        value={password}
        onChange={(e) => setPassword(e.target.value)}
      />
      <button type="submit">Login</button>
    </form>
  );
};

export default Login;
```

基本的にsignupの方とほぼコードは変わらず、呼び出しているメソッドsupabase.auth.signInに変わっています。

### 5. ログアウト機能の実装

components/Header.tsxファイルを作成し、ログアウトボタンを含むヘッダーを実装します。

```components/Header.tsx
import { supabase } from '../lib/supabase';

const Header = () => {
  const handleLogout = async () => {
    const { error } = await supabase.auth.signOut();
    if (error) {
      console.error(error.message);
    } else {
      console.log('User logged out');
    }
  };

  return (
    <header>
      <button onClick={handleLogout}>Logout</button>
    </header>
  );
};

export default Header;
```

ログアウトは、supabase.auth.signOut()を使用して、SupabaseのsignOutメソッドを呼び出し、ユーザーをサインアウトします。このメソッドは、認証セッションを終了させます。

ログアウトが成功すると、コンソールに「User logged out」と表示されます。エラーが発生した場合は、エラーメッセージがコンソールに表示されます。

## おわりに

Next.jsとSupabase Authを使用して、基本的な認証機能（ユーザー登録、ログイン、ログアウト）を実装する方法を紹介しました。

今回基本的な認証機能のみなため、次のステップとしては独自のカスタム機能や追加のセキュリティ対策を実装していく感じになりそうです。

Supabaseは認証機能以外にも、リアルタイムデータベースやストレージ、エッジ関数など、さまざまな機能を提供しているので、これらの機能も活用して色々できそうです。

## JISOUのメンバー募集中！
プログラミングコーチングJISOUでは、新たなメンバーを募集しています。
実践的なカリキュラムで、あなたのエンジニアとしてのキャリアを最短で飛躍させましょう！
実践重視：即戦力を育てるアウトプット中心のプログラム。
モダンなスキル : Reactを中心としたモダンな技術を学べる。
キャリアアップ：スキルアップだけでなく、キャリアパスのサポートも充実。
興味のある方は、ぜひホームページからお気軽にカウンセリングをお申し込みください！
▼▼▼

https://projisou.jp/