Firebase Admin SDKは、サーバーやCI、バッチなど信頼できる環境から、管理者権限でFirebaseを操作するためのライブラリです。ブラウザやスマホアプリに組み込む通常のFirebase SDK(クライアントSDK)とは別物で、ユーザーの作成・削除、カスタムクレームの付与、IDトークンの検証、FCMの送信を、セキュリティルールの制約を受けずに実行できます。
2026年6月8日公開のNode.js版14.0.0で、admin.auth() のような名前空間形式の書き方が削除され、Node.js 18と20のサポートも終わりました。この記事は、2026年10月18日時点の最新版(Node.js版14.5.0/Python版7.7.0)を前提に、導入と初期化、よく使う操作、失敗しやすい箇所を整理します。初期化の挙動はNode.js版の複数の版で、Authの操作と失効チェックはNode.js版とPython版をFirebase Local Emulator Suiteにつないで、それぞれ実行して確かめました。FCM送信の例とJava・Go・C#は実行していません。
まとめ:Firebase Admin SDKの要点
- 役割:サーバー側で管理者権限を持って動くSDK。クライアントSDKと違い、Firestore・Realtime Databaseのセキュリティルールを通りません。
- 対応言語:Node.js・Java・Python・Go・C#(.NET)の5言語と、実験版のDart。全機能を使えるのはNode.jsだけです。
- 動作要件:Node.js版は22以上、Go版は1.25以上。日本語版の公式ページは「Node.js 18以降」「Go 1.23以降」のまま更新が止まっているため、英語版で確認してください。
- 初期化:Cloud Run・Cloud Functions・App Hostingでは引数なしの
initializeApp()で済みます。鍵JSONを使う構成では、getApps()で既存のアプリを再利用しないと2回目の呼び出しでエラーになります。 - v14の書き方:
admin.auth()はgetAuth()、admin.firestore()はgetFirestore()へ。読み込み元はfirebase-admin/appなどのサブパスです。 - 落とし穴:
verifyIdToken()は既定で失効を確認しません。しかもエミュレーター上の挙動はNode.js版とPython版で逆になるため、ローカルのテスト結果を本番の挙動とみなせません。
Firebase Admin SDKとクライアントSDKの違い
「Firebase SDK」と呼ばれるものは、実行場所と権限で2系統に分かれます。アプリ利用者の端末で動くのがクライアントSDK、開発者が管理するサーバーで動くのがAdmin SDKです。クライアントSDKの導入手順はFirebaseのプロジェクト作成からSDK導入までの手順で扱っており、この記事はサーバー側に絞ります。
| 比較軸 | クライアントSDK | Admin SDK |
|---|---|---|
| 実行場所 | ブラウザ・iOS・Android | サーバー・CI・バッチ |
| パッケージ(JS) | firebase | firebase-admin |
| 認証の主体 | ログイン中のユーザー | サービスアカウント |
| セキュリティルール | 適用される | 適用されない |
| 他人のアカウント操作 | 不可 | 作成・更新・削除できる |
| 設定値の公開 | apiKey等は公開前提 | 鍵は秘匿が必須 |
Firestoreのクライアントライブラリの説明は、サーバー用のライブラリがセキュリティルールをすべて迂回し、Application Default Credentialsで認証すると明記しています。Admin SDKのコードでは、ルールに頼らず入力検証と権限確認をサーバー側で行う必要があります。なおRealtime Databaseに限っては、初期化時に databaseAuthVariableOverride で特定のuidを名乗らせ、ルールの制限を受けたまま読み書きさせる方法も用意されています。
対応言語と最新版・動作要件
各言語の最新版は、2026年10月18日にパッケージレジストリから確認した値です。9月23〜24日に全言語がそろって更新されて以降、新しい版は出ていません。
| 言語 | パッケージ | 最新版 | 動作要件 | リポジトリ |
|---|---|---|---|---|
| Node.js | firebase-admin(npm) | 14.5.0 | Node.js 22以上 | firebase-admin-node |
| Python | firebase-admin(PyPI) | 7.7.0 | 3.9以上(3.9は非推奨) | firebase-admin-python |
| Java | com.google.firebase:firebase-admin | 9.11.0 | Java 8以上 | firebase-admin-java |
| Go | firebase.google.com/go/v4 | v4.22.0 | Go 1.25以上 | firebase-admin-go |
| C#(.NET) | FirebaseAdmin(NuGet) | 3.7.0 | .NET 8.0以上を推奨 | firebase-admin-dotnet |
| Dart | 実験版 | – | Dart SDK 3.9以上 | – |
動作要件は英語版のセットアップページ(2026年10月13日更新)に合わせています。日本語版の同じページは最終更新が2026年3月31日で、Node.jsは「18以降(20以降を推奨)」、Goは「1.23以降」と書かれたままです。日本語版を見てNode.js 20で環境を組むと、14系の動作対象から外れます。Python 3.9で7.7.0を動かすと、依存するgoogle-authが「サポート終了済みのPython」という警告を出しました。新規に組むなら3.10以上を選んでください。
対応言語別の非対応機能
セットアップページの機能表を見ると、認証まわり(カスタムトークン発行・IDトークン検証・ユーザー管理・カスタムクレーム・マルチテナント)とFCM送信は全言語で使えます。差が出るのはそれ以外です。
| 言語 | 使えない主な機能 |
|---|---|
| Node.js | なし(全機能に対応) |
| Python | SQL Connect、セキュリティルール管理、Extensions |
| Java | SQL Connect、Cloud Tasks連携、ルール管理、App Check |
| Go | SQL Connect、Cloud Tasks連携、プロジェクト管理、ルール管理 |
| C#(.NET) | Firestore、Realtime Database、Cloud Storage、Remote Config |
Go版のRealtime Databaseはリアルタイムのイベントリスナーに対応せず、明示的な読み取りで最新値を取りに行く必要があります。.NETでFirestoreを使う場合は、Admin SDKではなく Google.Cloud.Firestore を別に導入します。
導入と初期化の手順
インストールは各言語のパッケージマネージャーで1行です。Node.jsなら npm install firebase-admin、Pythonなら pip install firebase-admin、Goなら go get firebase.google.com/go/v4 を実行します。初期化の方法は、実行環境がGoogleのサービス上かどうかで分かれます。
Google環境:引数なしの初期化(ADC)
Cloud Run・App Engine・Cloud Functions for Firebase・Firebase App Hostingでは、Application Default Credentials(ADC)が実行環境のサービスアカウントを自動で見つけます。公式はこの方法を「強く推奨」としており、鍵ファイルも環境変数も要りません。
import { initializeApp } from 'firebase-admin/app';
import { getAuth } from 'firebase-admin/auth';
import { getFirestore } from 'firebase-admin/firestore';
const app = initializeApp();
const auth = getAuth(app);
const db = getFirestore(app);
Pythonでは次のように書きます。
import firebase_admin
from firebase_admin import auth, firestore
app = firebase_admin.initialize_app()
db = firestore.client()
Realtime DatabaseのURLなど追加の設定は、環境変数 FIREBASE_CONFIG で渡せます。値が { で始まればJSONとして、そうでなければJSONファイルのパスとして読まれます。App HostingとCloud Functions for Firebaseでは、この変数が自動で設定されます。
Google外の環境:サービスアカウント鍵(JSON)と環境変数
オンプレミスや他社クラウドでは、Firebaseコンソールの「プロジェクトの設定」→「サービス アカウント」で「新しい秘密鍵の生成」を押し、JSONファイルを取得します。公式は、コードに鍵のパスを直書きするより、環境変数 GOOGLE_APPLICATION_CREDENTIALS にパスを入れる方法を「より安全」としています。
export GOOGLE_APPLICATION_CREDENTIALS="/secure/path/service-account.json"
ファイルを置けないホスティングでは、鍵JSONの中身を環境変数に分けて渡す構成がよく使われます。このとき秘密鍵の改行が \n という2文字のまま届くと、14.5.0では cert() を呼んだ時点で app/invalid-credential(Failed to parse private key.)になりました。読み込み時に改行へ戻してから渡します。
import { initializeApp, cert } from 'firebase-admin/app';
initializeApp({
credential: cert({
projectId: process.env.FIREBASE_PROJECT_ID,
clientEmail: process.env.FIREBASE_CLIENT_EMAIL,
privateKey: process.env.FIREBASE_PRIVATE_KEY.replace(/\\n/g, '\n')
})
});
環境変数の設定方法そのものは環境変数の設定方法とDocker・CIでの受け渡しを参照してください。鍵が漏れると、そのサービスアカウントに付与された権限で第三者に操作されるおそれがあります。付与するIAM権限は必要最小限にしてください。Google Cloudでは、2024年5月3日以降に作成された組織で制約 iam.disableServiceAccountKeyCreation(マネージド制約では iam.managed.disableServiceAccountKeyCreation)が既定で有効になり、そもそも鍵を発行できません(サービスアカウント鍵の作成と削除)。GitHub ActionsからFirebaseを操作する用途なら、鍵を作らずに済むgoogle-github-actionsのWorkload Identity連携へ移す方が安全です。
ローカル開発:gcloudの認証情報とプロジェクトID
開発機から本番プロジェクトにつなぐ場合、鍵を発行せずに gcloud auth application-default login で得たADCを使えます。ただしセットアップページによると、Firebase AuthenticationはgcloudのOAuthクライアントIDで作られた認証情報を受け付けず、この種の認証情報ではプロジェクトIDの指定も必要です。そのためAuthを使うなら、種類が「デスクトップアプリ」のOAuthクライアントIDを自分で作り、--client-id-file に渡してADCを作り直します。プロジェクトIDは初期化時の projectId か、環境変数 GOOGLE_CLOUD_PROJECT で渡します。環境変数で渡せばコードを変えずに済みます。--client-id-file を使うと、APIの課金と割り当てはそのクライアントIDを持つプロジェクトに付きます(gcloudのリファレンス)。
gcloud auth application-default login --client-id-file=./client_secret.json
export GOOGLE_CLOUD_PROJECT=my-project-id
本番のデータに触れずに試すだけなら、エミュレーターに demo- で始まるプロジェクトIDでつなぐ方が手軽です。認証情報を用意する必要がなく、誤って本番のユーザーを消す事故も起きません。構成はFirebase Local Emulator Suiteの使い方にまとめています。
二重初期化のエラーと複数アプリの初期化
開発サーバーのホットリロードやサーバーレスの関数で、モジュールが読み直されて initializeApp() が2回呼ばれることがあります。このときの挙動は13.5.0(2025年8月28日)で変わりました。リリースノートの「initializeApp idempotency」です。複数の版で同じコードを実行した結果は次のとおりです。
| 2回目の呼び出し | 13.4.0以前 | 13.5.0以降(14.5.0も同じ) |
|---|---|---|
| 引数なし → 引数なし | app/duplicate-app | 既存のアプリを返す |
| 同じ設定値(projectIdなど) | app/duplicate-app | 既存のアプリを返す |
| 違う設定値 | app/duplicate-app | app/duplicate-app |
| credential: cert(…) 付き | app/duplicate-app | app/invalid-app-options |
注意すべきは最後の行です。鍵JSONを cert() で渡す構成は、同じ鍵でも2回目に必ず失敗します。SDKが認証情報オブジェクトの同一性を判定できないためで、エラーメッセージ自体が getApp か getApps での再利用を指示しています。既定のアプリ(名前は [DEFAULT])があればそれを使う形にしておけば、版にもリロードにも左右されません。
import { initializeApp, getApps, cert } from 'firebase-admin/app';
const app = getApps().find((a) => a.name === '[DEFAULT]')
?? initializeApp({ credential: cert(serviceAccount) });
よく見かける getApps().length ? getApp() : initializeApp(...) は、名前付きのアプリだけが先に作られていると getApp() が app/no-app で失敗します。getApps() は名前付きのアプリも含めて返すためです。上の形なら、名前付きのアプリが先にあっても、2回呼んでも同じ既定のアプリが返ることを14.5.0で確認しました。
開発用と本番用など、2つのプロジェクトを1つのプロセスから操作したい場合は、第2引数にアプリ名を付けて別のアプリとして初期化します。getAuth(other) のように、各サービスの取得時にアプリを渡します。
const other = initializeApp({ credential: cert(otherServiceAccount) }, 'other');
const otherAuth = getAuth(other);
v14で変わった書き方と移行手順
Node.js版14.0.0のリリースノートは、破壊的変更として「非推奨だった名前空間形式の削除」「Node.js 18と20のサポート終了」「Instance IDサービスの削除」「旧FCM型の削除」を挙げています。14.5.0を読み込むと、admin.auth と admin.firestore はどちらも undefined でした。旧形式のコードは、次の対応表のとおり書き換えます。
| v13以前の書き方 | v14の書き方 | 読み込み元 |
|---|---|---|
| admin.initializeApp() | initializeApp() | firebase-admin/app |
| admin.credential.cert(key) | cert(key) | firebase-admin/app |
| admin.auth() | getAuth() | firebase-admin/auth |
| admin.firestore() | getFirestore() | firebase-admin/firestore |
| admin.firestore.FieldValue | FieldValue | firebase-admin/firestore |
| admin.database() | getDatabase() | firebase-admin/database |
| admin.messaging() | getMessaging() | firebase-admin/messaging |
| sendMulticast() | sendEachForMulticast() | 13.0.0で旧APIを削除 |
移行は3段階で進めると安全です。まず実行環境をNode.js 22以上に上げます。Cloud Functionsなら package.json の engines も合わせて変更してください。次に13系のまま書き方だけをサブパス形式へ直し、テストを通します。最後に14系へ上げます。書き方の変更と版の更新を同時に行うと、どちらが原因で落ちたのか切り分けられなくなります。
ユーザー管理とIDトークン検証の実装
Admin SDKの代表的な用途に、Firebase Authenticationのユーザーをサーバーから操作する処理があります。ログイン方式の選び方など認証そのものはFirebase Authenticationの認証方式と導入手順を参照してください。会員基盤の設計から任せたい場合は、一創の認証基盤・ID管理システム開発でも相談を受けています。
ユーザーの作成・更新・削除と一括処理の上限
以降のNode.jsコード例は、導入章の初期化を実行済みの環境で使う処理の抜粋です。各例を別ファイルで実行する場合は初期化処理と必要なimportを追加し、idToken・uid・fidListには処理対象の値を渡してください。
import { getAuth } from 'firebase-admin/auth';
const auth = getAuth();
const user = await auth.createUser({
email: '[email protected]',
password: 'secret-pass-1',
displayName: '山田太郎'
});
await auth.updateUser(user.uid, { emailVerified: true });
await auth.deleteUser(user.uid);
一括処理には1回あたりの上限があり、超えると例外になります。エミュレーターで上限を1件超えて呼ぶと、いずれも実行前にエラーで止まりました。
| メソッド | 1回の上限 | 超えたときのエラー |
|---|---|---|
| listUsers | 1,000件 | auth/argument-error |
| getUsers | 100件 | auth/maximum-user-count-exceeded |
| deleteUsers | 1,000件 | auth/maximum-user-count-exceeded |
1,000件を超えるユーザーを全件たどるには、戻り値の pageToken を次の呼び出しに渡して繰り返します。エミュレーターに5件を作り、1回2件ずつ取ると3回で5件を取り切りました。Python版は auth.list_users().iterate_all() がページ送りを内部で行います。
let pageToken;
do {
const res = await getAuth().listUsers(1000, pageToken);
res.users.forEach((u) => console.log(u.uid, u.email));
pageToken = res.pageToken;
} while (pageToken);
deleteUsers() には別の注意点もあります。ユーザー管理のドキュメントのとおり、一括削除ではCloud Functions for Firebaseの削除トリガー(onDelete())が発火しません。退会時に関連データを消す処理をトリガーに任せているなら、1件ずつ deleteUser() で消す必要があります。
IDトークンの検証と失効チェック
クライアントがログイン後に送ってくるIDトークンを、サーバー側で検証して利用者を特定します。Node.jsとPythonでは次のように書きます。
const decoded = await getAuth().verifyIdToken(idToken, true);
console.log(decoded.uid, decoded.role);
decoded = auth.verify_id_token(id_token, check_revoked=True)
Node.jsの第2引数 true とPythonの check_revoked=True が失効チェックです。省略時も署名・有効期限・対象プロジェクト・発行者などは検証しますが、失効は確認しません。revokeRefreshTokens(uid) で強制ログアウトさせたユーザーのトークンも、有効期限(発行から1時間)までは通ります。付けると失効済みのトークンは拒否されますが、検証のたびにAuthenticationのバックエンドへの問い合わせが発生します(セッション管理のドキュメント)。管理画面や決済など、即時に遮断したい処理にだけ付ける使い分けが現実的です。
紛らわしいのはエミュレーターの挙動です。firebase-tools 15.34.0のAuth Emulator(プロジェクトID demo-x、FIREBASE_AUTH_EMULATOR_HOST で接続)でトークンを発行し、2秒待ってから revokeRefreshTokens() で失効させました。同じ失効済みトークンを、失効チェックの有無を変えてNode.js版とPython版で検証した結果が次の表です。
| 失効後のトークンの検証 | Node.js 14.5.0 | Python 7.7.0 |
|---|---|---|
| 失効チェックなし | 拒否(auth/id-token-revoked) | 通る |
| 失効チェックあり | 拒否(auth/id-token-revoked) | 拒否(RevokedIdTokenError) |
Node.js版はソースにエミュレーター接続時は常に失効を確認する分岐があり、Python版には無いためです。Node.jsで書いたテストは、第2引数を付け忘れてもエミュレーターでは失効が効いているように見え、本番では失効済みのトークンが通ります。失効チェックの有無は、エミュレーターの結果ではなくコードレビューで確かめてください。
カスタムクレームによるロール管理
ユーザーに role: 'editor' のような属性を持たせ、IDトークンに載せる仕組みがカスタムクレームです。
await getAuth().setCustomUserClaims(uid, { role: 'editor' });
このAPIは既存のカスタムクレーム全体を上書きします。残したい属性がある場合は、既存値を確認して更新内容に含めてください。ほかに次の制約があります(カスタムクレームのドキュメント)。1つ目はサイズで、JSONにして1,000バイトを超えると auth/claims-too-large になります。2つ目は名前で、sub などOIDCやFirebaseの予約済みの名前を使うと auth/reserved-claim になります。3つ目は反映の時期で、クレームが載るのは次にIDトークンが発行されたときです。ロールを付けた直後に効かせたいなら、クライアント側で getIdToken(true) を呼んでトークンを更新させます。ただしこれはクライアントの協力が前提で、古いトークンを送り続けられると新しいクレームに切り替わりません。権限を剥奪するときは、revokeRefreshTokens() と失効チェック付きの検証でサーバー側から遮断します。プロフィールのような大きなデータはクレームに入れず、Firestoreに置いてください。
FCMの送信とFID移行への対応
Admin SDKからは、FCM(Firebase Cloud Messaging)の通知を送れます。2026年はFCMの宛先が、デバイスの登録トークンからFID(Firebase Installation ID)へ切り替わる移行期間です。Node.js版14.1.0で送信APIに fid が加わり、token は非推奨になりました。
import { getMessaging } from 'firebase-admin/messaging';
const res = await getMessaging().sendEachForMulticast({
fids: fidList,
notification: { title: '在庫が入荷しました', body: 'お気に入りの商品が購入できます' }
});
console.log(res.successCount, res.failureCount);
宛先にするFIDは、クライアント側のFCM SDKがFIDでFCMに登録したものに限ります(Admin SDKでの送信ガイド)。sendEachForMulticast() で1回に渡せる宛先は500件までです。移行期間中は tokens フィールドにFIDを入れても受け付けられます。旧APIの sendAll() と sendMulticast() はNode.js版13.0.0、Python版7.0.0で削除済みです。通知の仕組みや送信上限、Android・iOS側のFID対応はFCMの仕組みと送信方法・FID移行で詳しく扱っています。
FirestoreとRealtime Databaseの操作
データベースの読み書きは、Firestoreなら getFirestore()、Realtime Databaseなら getDatabase() から行います。以下はFirestoreのサーバー用APIの例です。WebのモジュラーSDKとは呼び出し方が異なり、アクセス制御にはセキュリティルールではなくIAMを使います。
import { getFirestore, FieldValue } from 'firebase-admin/firestore';
const db = getFirestore();
await db.collection('orders').doc('o1').set({
total: 1200,
createdAt: FieldValue.serverTimestamp()
});
const snap = await db.doc('orders/o1').get();
console.log(snap.data().total);
Firestoreの料金は、Admin SDKからの操作でもクライアントSDKと同じく、ドキュメントの読み取り・書き込み・削除の件数と保存容量などで決まります(Firestoreの料金)。無料枠は1プロジェクト1データベースに限られ、読み取りは1日5万件までです。バッチで全件を走査する処理は、件数に比例して費用がかかります。データモデルと課金の考え方はCloud Firestoreの仕組みと料金を参照してください。PostgreSQLを使うFirebase SQL Connect(旧Data Connect)は、Node.js版のAdmin SDKからだけ操作できます。
Admin SDKを置いてはいけない場所と典型的な失敗
Admin SDKは権限が強いぶん、置き場所を誤ると被害が大きくなります。次の4つは避けてください。
- フロントエンドやモバイルアプリへの同梱:firebase-adminはサーバー用で、ブラウザでは動きません。Next.jsでは
'use client'のコンポーネントから読み込まず、Route HandlerやServer Actionsなどサーバー側のコードに閉じ込めます。 - 鍵JSONのリポジトリへのコミット:非公開リポジトリでも、CIのログやフォークから漏れます。鍵ファイルは
.gitignoreに入れ、CIではWorkload Identity連携かシークレット管理を使います。 - ルールがあるから安全という思い込み:Admin SDK経由の書き込みにはルールが効きません。APIの入口で
verifyIdToken()とクレームを確認し、そのユーザーに許された操作かを判定してからデータベースに触れます。 - 古いNode.jsのままでのバージョン更新:14系は
package.jsonのenginesにnode: ">=22"を宣言しています。npmは設定によって警告だけでインストールを通すことがありますが、動作保証はありません。
逆に、ユーザーが自分のデータを読み書きするだけの処理にAdmin SDKは不要です。クライアントSDKとルールで完結させた方が、サーバーの運用も権限の管理も減ります。Admin SDKは、他人のデータに触れる処理、ルールでは表現できない検証、トークン発行や通知送信に絞るのが適切です。
よくある質問
Firebase Admin SDKとFirebase SDKの違いは何ですか?
Firebase SDK(クライアントSDK)は利用者の端末で動き、ログイン中のユーザーの権限でセキュリティルールに従って動作します。Admin SDKはサーバーで動き、サービスアカウントの管理者権限でルールを通らずに操作します。
firebase-adminの最新バージョンはいくつですか?
2026年10月18日時点で、Node.js版は14.5.0(2026年9月23日公開)、Python版は7.7.0です。Node.js版は14系からNode.js 22以上が必要です。
サービスアカウントのJSONはどこで取得しますか?
Firebaseコンソールの「プロジェクトの設定」→「サービス アカウント」→「新しい秘密鍵の生成」から取得します。Cloud RunやCloud Functionsで動かす場合は鍵が不要で、引数なしの initializeApp() で初期化できます。
The default Firebase app already exists と表示されるのはなぜですか?
13.4.0以前の版で initializeApp() を2回呼んだときのメッセージです。13.5.0以降は同じ設定なら既存のアプリが返りますが、cert() で鍵を渡す構成は今も2回目で失敗します。getApps().find((a) => a.name === '[DEFAULT]') ?? initializeApp(...) のように、既定のアプリがあれば再利用する形にしてください。
Firebase Admin SDKはPythonやJavaでも使えますか?
使えます。Python・Java・Go・C#(.NET)に公式版があり、認証とFCM送信は全言語で共通です。ただしC#版はFirestoreとRealtime Databaseに対応していないなど、Node.js以外は一部の機能が使えません。