Supabaseのメール認証を詳しく紹介

2022年12月15日木曜日

Supabase

t f B! P L

Supabaseはいわゆる BaaS (Backend As A Service)で、ちまたでは Firebase の RDB(PostgreSQL)版と言われる。 そして Firebaseと同様に認証機能も備わっており、基本のメールアドレス・パスワード認証、マジックリンク、Googleを始めとする大手サービスや各種SNSアカウントでのログインをサポートしている。

今回は、Supabaseの認証機能を使って、基本的なメールアドレス・パスワード認証をするログイン画面を作ってみたいと思う。

スポンサーリンク

メールアドレスとパスワード認証

ユーザー登録(サインアップ)

まず最初に、ユーザーを登録するサインアップ画面を作ってみる。

ユーザーの登録は、Supabaseクライアント auth ライブラリの signUp 関数を使い、引数にメールアドレスとパスワードを指定する。

可読性のため、下記のサンプルソースでは、パスワードとパスワード(確認)の一致性チェックなど、一部の必要なチェック処理は省いているので、そのまま使う場合は気を付けてください。

また、パスワードの文字数は、規定では6以上指定する必要がある。(後述するオプションで変更が可能)

function SignUp() {

  const [email, setEmail] = useState("")
  const [password, setPassword] = useState("")
  const [passwordConf, setPasswordConf] = useState("")

  //ユーザーの登録
  const onSubmit = async (e) => {
    e.preventDefault()

    const { data, error } = await supabase.auth.signUp({
      email: email,
      password: password,
    })

    if (error) {
      throw error;
    }
  }

  return (
    <section>
      <form onSubmit={onSubmit}>
        <div>
          <label>メールアドレス</label>
          <input type="email" 
            required value={email} 
            onChange={e => setEmail(e.target.value)} 
          />
        </div>
        <div>
          <label>パスワード</label>
          <input type="password" 
            required value={password} 
            onChange={e => setPassword(e.target.value)} 
          />
        </div>
        <div>
          <label>パスワード(確認)</label>
          <input type="password" 
            required value={passwordConf} 
            onChange={e => setPasswordConf(e.target.value)} 
          />
        </div>
        <div>
          <button type="submit">サインアップ</button>
        </div>
      </form>
    </section>
  )
}

export default SignUp;

登録ボタンで supabase.auth.signUp を呼び出すと、次のようなアドレス確認メールが送信され、「Confirm your mail」のリックを押すと、ユーザーの登録が行われる。

enter image description here
※送信されるメールの文面は、後述するオプションの設定で変更可能である。

ログイン(サインイン)

次に、登録したユーザーの認証を行うログイン画面を作る。

メールアドレス・パスワードでの認証はSupabaseクライアントの signInWithPassword 関数を用いて行う。引数には、メールアドレスとパスワードを指定する。

function SignIn() {

  const [email, setEmail] = useState("")
  const [password, setPassword] = useState("")

  const onSubmit = async (e: FormEvent) => {
    e.preventDefault()

    const { data, error } = await supabase.auth.signInWithPassword({
      email: email,
      password: password,
    })

    if (error) {
      throw error;
    }
  }

  return (
    <section>
      <form onSubmit={onSubmit}>
        <div>
          <label>メールアドレス</label>
          <input type="email" 
            required value={email} 
            onChange={e => setEmail(e.target.value)} 
          />
        </div>
        <div>
          <label>パスワード</label>
          <input type="password" 
            required value={password} 
            onChange={e => setPassword(e.target.value)} 
          />
        </div>
        <div>
          <button type="submit">ログイン</button>
        </div>
      </form>
    </section>
  )
}


export default SignIn;

認証に成功すると HTTP 200 で応答が返り、変数 data にセッションおよびログインしたユーザーの情報が入る。

enter image description here

認証に失敗すると、HTTP 400 となり、変数 error にエラー内容が格納される。

enter image description here

スポンサーリンク

ログイン状態の確認

現在ログインされているユーザー情報を取得する方法は、大きく2つある。

1つ目は、auth ライブラリの getSession() 関数を使って、必要なタイミングでログインしているユーザーのセッション情報を取得する方法である。

const { data: { session }, error } = await supabase.auth.getSession()

ユーザーがログインしている状態で関数を実行すると、次のように、セッション情報およびユーザー情報が取得できる。ログインされていない状態で関数を実行した場合は null が返却される。
enter image description here

2つ目は、onAuthStateChange を使って認証状態を監視し、状態が変わった時にコールバック関数を呼び出す方法がある。ログインの状態によって画面表示を切り替えるシーンなどで便利な方法である。

  supabase.auth.onAuthStateChange((event, session) => {
    console.log(session)
    if (event == "SIGNED_IN") {
      console.log("ログインしました")
    } if (event == "SIGNED_OUT") {
      console.log("ログアウトしました")
    }
  })

パスワードのリセット

パスワードをリセットするする場合は、リセット用のメールの送信、メール文面のリンクよりパスワードを設定する画面を表示、入力された新しいパスワードで更新という流れを踏む必要がある。

順に、実装方法のサンプルコードを紹介する。

パスワードリセット送信画面の作成

まず、指定したメールアドレスに、パスワードをリセットするためのメールを送る画面を作る。

パスワードリセットのメールは、auth ライブラリの resetPasswordForEmail() 関数を使い送信する。第1引数には送信先のメールアドレス、第2引数のオプションには、メールの文中にあるパスワードリセットのリンクを押した後のリダイレクト先を指定する。リダイレクト先には通常、新しいパスワードを設定するためのパスワード変更画面へのURLを指定する。

function PasswordReset() {
  const [email, setEmail] = useState("")

  const onSubmit = async (e: FormEvent) => {
    e.preventDefault()

    const { data, error } = await supabase.auth.resetPasswordForEmail(email, {
      redirectTo: `http://localhost:3000/new-password`
    })

    if (error) {
      throw error;
    }

    console.log("メールを送信しました。")
  }

  return (
    <section>
      <form onSubmit={onSubmit}>
        <div>
          <label>メールアドレス</label>
          <input type="email" 
            required value={email} 
            onChange={e => setEmail(e.target.value)} 
          />
        </div>
        <button type="submit">メールを送信</button>
      </form>
    </section>
  )
}

export default PasswordReset;

「メールを送信」を押すと、次の内容のメールが指定したメールアドレスに送信される。「Reset Password」のリンクをクリックすると、Supabaseで該当ユーザーのパスワードがリセットされた後、redirectTo で指定した URLにリダイレクトされる。

enter image description here
※送信されるメールの文面は、後述するオプションの設定で変更可能である。

パスワード変更画面の作成

メールのリンクでパスワードをリセットした後に表示する、パスワード変更画面を作成する。

パスワードを含むユーザーの情報の変更は、auth ライブラリの updateUser() 関数を使用する。

function NewPassword() {
  const [password, setPassword] = useState("")
  const [passwordConf, setPasswordConf] = useState("")

  const onSubmit = async (e: FormEvent) => {
    e.preventDefault()

    const { data, error } = await supabase.auth.updateUser({
      password: password
    }) 

    if (error) {
      throw error;
    }

    console.log("パスワードを変更しました。")
  }

  return (
    <section>
      <form onSubmit={onSubmit}>
        <div>
          <label>パスワード</label>
          <input type="password"
            required value={password}
            onChange={e => setPassword(e.target.value)}
          />
        </div>
        <div>
          <label>パスワード(確認)</label>
          <input type="password"
            required value={passwordConf}
            onChange={e => setPasswordConf(e.target.value)}
          />
        </div>
        <button type="submit">パスワードを変更</button>
      </form>
    </section>
  )
}

export default NewPassword;

スポンサーリンク

ログアウト(サインアウト)

ログアウトは、auth ライブラリの signOut() 関数を使う。

const onLogout = async () => {
  const { error } = await supabase.auth.signOut()
  if (error) {
    throw error;
  }
}

console.log("ログアウトしました")

オプションの設定

メール文面の変更

ユーザー登録時の確認メールや、パスワードリセット時のメールなど、Supabaseから送信される各種メールのテンプレートは、規定では英文になっている。

編集する場合は、[Authentication] → [Email Templates] の順でメニューを選択し、各タブのメールテンプレートを編集する。
enter image description here

各タブのメール送信内容は次のとおりである。

タブ 内容
Confirm signup ユーザー登録時のメールアドレス確認
Invite user 招待メール
Magic Link マジックリンク(パスワードレス)の認証用メール
Change Email Address メールアドレス変更時の確認メール
Reset Password パスワードリセット時の確認メール

メール認証のオプション

ユーザー登録時のメールアドレス確認要否、パスワードの最低文字数など、メールアドレス認証に関わる設定は、[Authentication] → [Providers] の順でメニューを選択した画面で変更できる。

メール認証で指定できるオプションは、次のとおり。

enter image description here

スポンサーリンク
スポンサーリンク

このブログを検索

Profile

自分の写真
Webアプリエンジニア。 日々新しい技術を追い求めてブログでアウトプットしています。
プロフィール画像は、猫村ゆゆこ様に書いてもらいました。

仕事募集もしていたり、していなかったり。

QooQ