WebTecNote

[JS] Firebaseの覚書 ⑨ 匿名認証の利用

Firebase Authentication に備わっている匿名ユーザーを作成する機能についてのメモ。
※ Firebaseの覚書には連番が付いてますが内容は繋がっていません。

永久アカウントと匿名アカウントの違い

匿名認証を利用すると、アカウント作成時にメールアドレスや他サービスの資格情報を利用しないので、認証後のユーザー情報で空になるものがいくつかある。

firebase.User

User {
  refreshToken: "..."
  uid: "..."
  displayName: null //←①
  photoURL: null
  email: null
  emailVerified: false
  phoneNumber: null
  isAnonymous: true //←②
  tenantId: null
  metadata: UserMetadata
  providerData: [] //←③
}

displayNameは OAuth系認証であればサービスで利用中の名前が設定されるが、匿名認証の場合は空になる。これはメールアドレス認証と同じで、アカウント作成時に名前を得る方法がないので設定されない。デフォルトのユーザー名を入れておきたいなら匿名認証後にユーザー情報を更新して設定しなければならない。

認証プロバイダを利用しないので providerData は空配列になる。

一番の違いは isAnonymous プロパティが true になることである。

admin.auth.UserRecord

匿名認証のアカウントに対して admin.auth().getUser()を使用した場合、戻り値の UserRecord も似たような感じで殆ど空になるが、
このデータには isAnonymous フラグが存在しない。

UserRecord {
  uid: '...',
  email: undefined,
  emailVerified: false,
  displayName: null,
  photoURL: undefined,
  phoneNumber: undefined,
  disabled: false,
  metadata: UserMetadata,
  passwordHash: undefined,
  passwordSalt: undefined,
  customClaims: undefined,
  tokensValidAfterTime: undefined,
  providerData: []
}

ProviderDataが空配列の時点で匿名認証だと判断できるが、
DecodedIdToken の firebase プロパティが 何で認証したかの情報を持っているので、verifyIdToken() などDecodedIdTokenが戻り値になる関数を利用するならプロパイダ名がanonymousかどうかで判断できる。

const decodedClaims = await admin.auth().verifyIdToken(idToken);

const isAnonymous = decodedClaims.firebase.sign_in_provider === 'anonymous';

匿名認証の利用

signInAnonymously を叩くだけ。これで匿名ユーザーが作成される。

const userCredential = await firebase.auth().signInAnonymously();

戻り値の UserCredential は次の通り。

{
   user: User,
   credential: null,
   additionalUserInfo: {
     providerId: null,
     isNewUser: true
   },
   operationType: "signIn"
}

匿名認証もFirebase的には他の認証方法でログインしたアカウントと同じ権限を持っている。
他の認証方法でログインしたユーザーと差別化を図るなら、User.isAnonymousプロパティがtrueかどうかで切り替えることになる。

匿名認証を永久アカウントに変換する

公式のドキュメントが妙に難解な書き方してあるが、要するに他の認証方法でログインさせてUserのlinkWith系メソッドで匿名アカウントにリンクさせれば良いだけのことである。

OAuth認証を利用する例

参考:Firebaseの覚書 ③ OAuth認証

// @type {AuthCredential}
let provider;

switch (providerName) {
  case 'google.com':
    provider = new firebase.auth.GoogleAuthProvider();
    break;
  case 'twitter.com':
    provider = new firebase.auth.TwitterAuthProvider();
    break;
  case 'facebook.com':
    provider = new firebase.auth.FacebookAuthProvider();
    break;
}

try {
  // @type {UserCredential}
  const { user } = auth.currentUser.linkWithPopup(provider);
} catch(e) {
  console.error(e);
}

メールアドレス・パスワード認証を利用する例

参考:Firebaseの覚書 ① メールアドレス認証

// @type {AuthCredential}
const credential = firebase.auth.EmailAuthProvider.credential(email, password);

try {
  // @type {UserCredential}
  const { user } = await firebase.auth().currentUser.linkWithCredential(credential);

  // 確認メールの送信
  await firebase.auth().currentUser.sendEmailVerification({
    handleCodeInApp: false
  });
} catch (e) {
  console.error(e);
}

参考リンク

モバイルバージョンを終了