Closed7

[キャッチアップ] supabase Auth

shingo.sasakishingo.sasaki

supabase の DB に普段お世話になってるけど、認証認可周りでも使ってみたいのでざっとドキュメントに目を通すスクラップ。

今回の目的はフロントエンドにメールアドレス/パスワードでのユーザー登録、ログインを提供することなので、主に Authentication、特にパスワード認証を中心に読み進める。

shingo.sasakishingo.sasaki

公式ドキュメントの Overview ざっと見る

https://supabase.com/docs/guides/auth

Auth には2種類ある

  • Authentication(認証): クライアントは誰なのか
  • Authorization(認可): クライアントに何をさせて良いのか

supabase Auth は他の supabase システムと組み合わせても良いし、スタンドアロンで動かしてもよい。基本的には Postgresql と統合した機能を提供する。

認証

認証方法は多数提供されてる

  • メールアドレス+パスワード
  • マジックリング
  • 電話番号
  • ソーシャル連携
    • Google
    • Twitter
    • GitHub
    • 他多数

認可

Postgresql の行レベルセキュリティ(RLS) による認可の設定が可能。
ポリシー機能によって SQL での柔軟な制約を定義できる。

例えば users テーブルに対して、 auth.uid() = user_id というポリシーを定義していれば、以下のようにクライアントから明示せずとも自身のユーザー情報しか取得できなくなるなど。

let { data, error } = await supabase.from('users').select('user_id, name')

// console.log(data)
// Still => { id: 'd0714948', name: 'Jane' }

この仕組みは以下の流れで実現している。

  • ユーザー登録が行われると、 auth.users テーブルにユーザー情報が登録される
  • supabase はユーザーの UUID を含んだ JWT をクライアントに渡す
  • クライアントはすべてのリクエストに JWT を含むようにする
  • Postgresql は JWT を認識し、どのユーザーからのリクエストかを特定する
  • Postgresql は auth.uid() という特殊な関数を通じて、SQLレベルで制限することができる

ユーザー管理

supabase は認証のためのエンドポイントを提供する

  • ユーザー登録
  • ログイン
    • パスワード
    • パスワードレス・ワンタイムパスワード
    • ソーシャル
  • ログアウト

ユーザーが登録されると、supabase はユーザーにユニークIDを付与する。この ID はデータベース内のどこからでも参照可能で、他のテーブルと結合して使用できる。

shingo.sasakishingo.sasaki

メールアドレス認証についてざっと確認

https://supabase.com/docs/guides/auth/auth-email

セットアップ

プロジェクトでメール認証を有効化する (デフォルトで有効化されてる?)
メールアドレスの確認プロセスと、アドレス変更時に新旧両アドレスでの確認プロセスを有効化する。

ユーザー登録

const { data, error } = await supabase.auth.signUp({
  email: 'example@email.com',
  password: 'example-password',
})

https://supabase.com/docs/reference/javascript/auth-signup

ログイン

async function signInWithEmail() {
  const { data, error } = await supabase.auth.signInWithPassword({
    email: 'example@email.com',
    password: 'example-password',
  })
}

https://supabase.com/docs/reference/javascript/auth-signinwithpassword

ログアウト

async function signOut() {
  const { error } = await supabase.auth.signOut()
}

https://supabase.com/docs/reference/javascript/auth-signout

shingo.sasakishingo.sasaki

軽く実装してみる

今まではデータベースしか使ってなくて、それも API サーバーからの利用だけだったので、JavaScript SDK を入れるとこから始まる。

https://supabase.com/docs/reference/javascript

インストール

$ yarn add @supabase/supabase-js

クライアントセットアップ

クライアントモジュールを作成して、とりあえずクライアント生成まで実装しちゃう。

import { createClient } from '@supabase/supabase-js'
const client = createClient(process.env['SUPABASE_URL'] || '', process.env['SUPABASE_KEY'] || '', {})

とりあえず supabase の情報は env からとって、オプションは指定せずデフォルトで進める。

ユーザー登録

適当にユーザー登録用関数を提供して試してみる。

export async function signUpByEmail(email: string, password: string) {
  const { data, error } = await client.auth.signUp({ email, password })
  console.log({ data, error })
  return { data, error }
}

これを正当なメールアドレスで呼び出してみると、確認用メールが飛んでくる。この文面は管理画面から変えられるみたい。

supabase のユーザー一覧画面で見ると、UUIDは既に発行されるけど、ステータスが Waiting for verification.. 状態になってる。

これをメール内の確認用URLを開くことで、有効化される。有効化されたあとは発行元URLのトップページにリダイレクトされるみたい。

ユーザーログイン

同様にログイン用の関数を用意して

export async function signInByEmail(email: string, password: string) {
  const { data, error } = await client.auth.signInWithPassword({ email, password })
  console.log({ data, error })
}

先程登録したユーザーを使ってこの関数を呼び出すと、 data に以下のような内容が含まれてる。

  • session
    • access_token
    • refresh_token
    • expires_at
    • expires_in
  • user
    • id
    • email
shingo.sasakishingo.sasaki

認証済みだとCookieに sb-access-token が入ってるけど、これは自サイトドメインに保存されてるから、Cookieのドメインが supabase になってても自サイトのAPIに対して送信できるんだっけか?

fetch の credentials オプションあたりの話な気もする。

shingo.sasakishingo.sasaki
export async function fetchSession() {
  const { data, error } = await client.auth.getSession()
  console.log(data)
}

これでCookieが保持してるアクセストークンからセッションを取得できるようになった。
オブジェクトでセッション情報が手に入ればあとは API サーバーに投げるだけで大丈夫そう。

このスクラップは2022/11/16にクローズされました