Firebase Authで登録,サインインやemail検証のカスタマイズをする場合の実装
Firebaseを使ってユーザー登録する時に、フロントから直接Firebaseとやりとりするとアプリケーション側のDBに反映させるタイミングがないなと思ったのでどうやるんだろうと思って調べたものを書いています。
Firebase側のプロジェクトの用意は済んだところからです。
Next.jsのコンポーネントで試しています。
登録・サインイン
import { FirebaseOptions, initializeApp } from "firebase/app";
import {
createUserWithEmailAndPassword,
getAuth,
signInWithEmailAndPassword,
} from "firebase/auth";
import { api } from "~/utils/api";
export default function Home() {
const firebaseConfig: FirebaseOptions = {
apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID,
};
initializeApp(firebaseConfig);
const auth = getAuth();
const email = process.env.NEXT_PUBLIC_EXAMPLE_EMAIL || "";
const password = process.env.NEXT_PUBLIC_EXAMPLE_PASSWORD || "";
const handleSignUp = async () => {
createUserWithEmailAndPassword(auth, email, password)
.then((userCredential) => {
const user = userCredential.user;
console.log("user", user);
})
.catch((error) => {
const errorCode = error.code;
const errorMessage = error.message;
console.log("errorCode", errorCode);
console.log("errorMessage", errorMessage);
});
};
const handleSignIn = async () => {
const userCredential = await signInWithEmailAndPassword(
auth,
email,
password
);
const user = userCredential.user;
console.log("user.emailVerified", user.emailVerified);
};
return (
<>
<div>
<button onClick={handleSignUp}>Sign up</button>
</div>
<div>
<button onClick={handleSignIn}>Sign in</button>
</div>
</>
);
}
登録
createUserWithEmailAndPassword()
でemail, passwordを使って登録。
パスワードの強度
Firebase側でチェックしてるのは文字数が6文字以上であるかだけ。
登録時のエラー
例えば、同一emailで登録済みの時
errorCode auth/email-already-exists
errorMessage Firebase: Error (auth/email-already-in-use).
サインイン
signInWithEmailAndPassword()
成功時のレスポンス
userとしては
失敗時のレスポンス
例えば、パスワードが違う時
errorCode auth/wrong-password
errorMessage Firebase: Error (auth/wrong-password).
email検証
以下のように、userを引数にsendEmailVerification()
を使ってfirebaseからemailを送信できる。
const handleSignUp = async () => {
createUserWithEmailAndPassword(auth, email, password)
.then((userCredential) => {
const user = userCredential.user;
sendEmailVerification(user);
})
};
メールに含まれるリンクにアクセスすることで、email検証が完了する。
リンクを踏んだ後の画面は以下。
email検証が完了しているかどうかはemailVerified
で分かる。
const user = userCredential.user;
console.log("user.emailVerified", user.emailVerified);
email検証カスタマイズ
検証emailの文面は変更できない。
リンク踏んだ後の画面も変更はできない。
このあたりをカスマイズするには、
- 検証URLの生成
- メールは独自で送信
する必要がある。
検証URLのBaseとなるURLはFirebaseコンソールで変更することができます。
Firebaseコンソール -> Templates -> メールアドレスの確認 -> 編集 -> アクションURL
ローカル環境で動作を試したいので、アクションURLをhttp://localhost:3000
に変更しました。
トークンを含めたemail検証リンクを生成するには、firebase-admin
のgenerateEmailVerificationLink()
を使います。
import * as admin from "firebase-admin";
...
if (!admin.apps[0]) {
await admin.initializeApp({
credential: admin.credential.cert({
projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
privateKey: process.env.FIREBASE_PRIVATE_KEY?.replace(/\\n/g, "\n"),
clientEmail: process.env.FIREBASE_CLIENT_EMAIL,
}),
});
}
const authAdmin = admin.auth();
const email = process.env.NEXT_PUBLIC_EXAMPLE_EMAIL || "";
const link = await authAdmin.generateEmailVerificationLink(email);
console.log("link", link);
...
ローカル環境でのfirebase-admin
の初期化はfirebase
の初期化と違って、サービスアカウントの情報を使います。
generateEmailVerificationLink()
した結果以下のように検証URLが生成されます。
link http://localhost:3000?mode=verifyEmail&oobCode=LB1upROfTggbM1M4YA3bbAzK0SaA62PkmC1ZnsUP4jIAAAGJrsW5oA&apiKey=AIzaSyDwUd_-eVxPObVudrEdBW7bM_2G6AiDrL4&lang=en
これを含めて独自でemail送信を行えばemail検証フローをカスタマイズできます。
上記URLへアクセスしたあとの検証方法は以下となります。
applyActionCode()
によってactionCodeを検証します。
import { FirebaseOptions, initializeApp } from "firebase/app";
import {
createUserWithEmailAndPassword,
getAuth,
signInWithEmailAndPassword,
checkActionCode,
} from "firebase/auth";
...
export default function Home() {
const firebaseConfig: FirebaseOptions = {
apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID,
};
initializeApp(firebaseConfig);
const auth = getAuth();
const searchParams = useSearchParams();
const actionCode = searchParams.get("oobCode");
useEffect(() => {
if (actionCode) {
applyActionCode(auth, actionCode)
});
}
}, [actionCode]);
...
applyActionCode(auth, actionCode)
を呼ぶとfirebase側のuser情報がemail検証済みの状態に変わります。
終わりに
emailの編集やパスワードリセットなどもactionCodeを使って実装できます。
Discussion