Line data Source code
1 : // Package firebase provides factories and helpers to initialize
2 : // the Firebase Admin SDK (Auth) for the application.
3 : package firebase
4 :
5 : import (
6 : "context"
7 : "fmt"
8 : "os"
9 :
10 : firebase "firebase.google.com/go/v4"
11 : "firebase.google.com/go/v4/auth"
12 : "google.golang.org/api/option"
13 : )
14 :
15 : // Credentials Config から必要な情報だけ受け取る形にしておくと依存が軽い
16 : type Credentials struct {
17 : // JSON資格情報のファイルパス or そのままJSON文字列
18 : CredsFile string // ex) "/work/keys/service-account.json"
19 : CredsJSON []byte // ex) 埋め込みやSecretから渡す場合
20 : ProjectID string // GCP プロジェクトID(無くても動くが明示推奨)
21 : }
22 :
23 : // Options は Firebase クライアントの動作設定を保持する構造体です。
24 : // 実環境またはエミュレータ環境のいずれを使用するかを指定します。
25 : type Options struct {
26 : // UseAuthEmulator は Firebase Authentication エミュレータを利用する場合に true に設定します。
27 : // false の場合は実際の Firebase プロジェクトに接続します。
28 : UseAuthEmulator bool
29 :
30 : // AuthEmulatorHost は Authentication エミュレータのホスト名またはアドレスを指定します。
31 : // 例: "localhost:9099"
32 : AuthEmulatorHost string
33 : }
34 :
35 : // NewAuthClient は Firebase Admin の *auth.Client を生成して返す
36 0 : func NewAuthClient(ctx context.Context, creds Credentials, opt Options) (*auth.Client, error) {
37 0 : var appOpts []option.ClientOption
38 0 :
39 0 : // 認証方法: ファイル or JSON(どちらか一方でOK)
40 0 : switch {
41 0 : case len(creds.CredsJSON) > 0:
42 0 : appOpts = append(appOpts, option.WithCredentialsJSON(creds.CredsJSON))
43 0 : case creds.CredsFile != "":
44 0 : appOpts = append(appOpts, option.WithCredentialsFile(creds.CredsFile))
45 0 : default:
46 : // GCE/GKE 等なら ADC (Application Default Credentials) にフォールバック
47 : }
48 :
49 0 : cfg := &firebase.Config{}
50 0 : if creds.ProjectID != "" {
51 0 : cfg.ProjectID = creds.ProjectID
52 0 : }
53 :
54 : // Emulator 対応(Admin SDKは環境変数を見る)
55 0 : if opt.UseAuthEmulator {
56 0 : host := opt.AuthEmulatorHost
57 0 : if host == "" {
58 0 : host = "localhost:9099"
59 0 : }
60 : // Admin SDK は FIREBASE_AUTH_EMULATOR_HOST を参照する。
61 : // セット失敗は致命ではない(後段の初期化で検出できる)ため握りつぶす。
62 : //_ = os.Setenv("FIREBASE_AUTH_EMULATOR_HOST", host)
63 0 : if err := os.Setenv("FIREBASE_AUTH_EMULATOR_HOST", host); err != nil {
64 0 : // ここで logger が使えない前提なので stderr に出す
65 0 : if _, e := fmt.Fprintf(os.Stderr,
66 0 : "warn: failed to set FIREBASE_AUTH_EMULATOR_HOST=%s: %v\n",
67 0 : host, err,
68 0 : ); e != nil {
69 0 : // stderr への出力すら失敗。ここでは致命ではないので変数を参照して「扱った」ことにする。
70 0 : // (staticcheck SA9003 対策)
71 0 : _ = e
72 0 : }
73 : }
74 0 : } else {
75 0 : // Emulator を使わないときは強制的に無効化
76 0 : if err := os.Unsetenv("FIREBASE_AUTH_EMULATOR_HOST"); err != nil {
77 0 : if _, e := fmt.Fprintf(os.Stderr,
78 0 : "warn: failed to unset FIREBASE_AUTH_EMULATOR_HOST: %v\n", err,
79 0 : ); e != nil {
80 0 : _ = e // staticcheck対策
81 0 : }
82 : }
83 : }
84 :
85 0 : app, err := firebase.NewApp(ctx, cfg, appOpts...)
86 0 : if err != nil {
87 0 : return nil, fmt.Errorf("firebase.NewApp: %w", err)
88 0 : }
89 :
90 0 : return app.Auth(ctx)
91 : }
|