The UNAUTHENTICATED error occurs when Firebase operations are attempted without valid authentication credentials. This commonly happens in Firestore, Realtime Database, and Cloud Functions when users are not signed in or security rules deny unauthenticated access.
Firebase returns the UNAUTHENTICATED error when the system cannot verify the identity of the caller making the request. Unlike PERMISSION_DENIED (which means the user is authenticated but lacks access rights), UNAUTHENTICATED means no valid authentication credentials were provided or the auth token is invalid. This error enforces Firebase security rules that restrict database operations to authenticated users only.
The most common cause is attempting to read/write Firestore or Realtime Database without signing in first. Always check authentication state before querying:
Web/JavaScript:
import { getAuth, signInAnonymously } from "firebase/auth";
import { getFirestore, collection, getDocs } from "firebase/firestore";
const auth = getAuth();
const db = getFirestore();
// Check if user is authenticated
if (!auth.currentUser) {
// Option 1: Sign in anonymously (allows database access)
await signInAnonymously(auth);
// Option 2: Redirect to login page
}
// Now database operations will work
const querySnapshot = await getDocs(collection(db, "users"));React with Firebase:
import { useAuth } from "./useAuth";
function MyComponent() {
const user = useAuth();
if (!user) {
return <div>Please sign in to continue</div>;
}
// Database queries here
}Admin SDK (Node.js) - Backend:
The Admin SDK uses a Service Account which automatically bypasses authentication:
const admin = require("firebase-admin");
admin.initializeApp({
credential: admin.credential.cert("/path/to/serviceAccountKey.json"),
});
const db = admin.firestore();
// Admin SDK automatically authenticates, no need to sign in
const docs = await db.collection("users").get();Check and update your Firestore or Realtime Database security rules to explicitly allow authenticated users:
Firestore Security Rules:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Allow authenticated users to read/write
match /{document=**} {
allow read, write: if request.auth.uid != null;
}
// More restrictive: only owner can access their data
match /users/{userId} {
allow read, write: if request.auth.uid == userId;
}
}
}Realtime Database Security Rules:
{
"rules": {
".read": "auth != null",
".write": "auth != null",
"users": {
"$uid": {
".read": "auth.uid == $uid",
".write": "auth.uid == $uid"
}
}
}
}To update rules:
1. Go to Firebase Console > Database > Rules tab
2. Paste the rules above
3. Click "Publish"
4. Test with Firebase Emulator Suite locally first
Cloud Functions marked as requiring authentication need a valid ID token. Ensure the user is signed in before calling:
Web/JavaScript:
import { getAuth, signInWithEmailAndPassword } from "firebase/auth";
import { getFunctions, httpsCallable } from "firebase/functions";
const auth = getAuth();
const functions = getFunctions();
// 1. Sign in the user
await signInWithEmailAndPassword(auth, email, password);
// 2. Call the function - auth token is automatically included
const myFunction = httpsCallable(functions, "myFunction");
const result = await myFunction({ data: "value" });Android/Kotlin:
// Sign in first
FirebaseAuth.getInstance().signInWithEmailAndPassword(email, password)
.addOnSuccessListener {
// Now call function
val functions = FirebaseFunctions.getInstance()
functions.getHttpsCallable("myFunction")
.call(mapOf("data" to "value"))
.addOnSuccessListener { result ->
Log.d("Function", "Success: ${result.data}")
}
.addOnFailureListener { exception ->
Log.e("Function", "Error: ${exception.message}")
}
}
.addOnFailureListener { exception ->
Log.e("Auth", "Sign in failed: ${exception.message}")
}iOS/Swift:
Auth.auth().signIn(withEmail: email, password: password) { result, error in
guard error == nil else { return }
// User is authenticated, call function
let functions = Functions.functions()
functions.httpsCallable("myFunction").call(["data": "value"]) { result, error in
guard error == nil else {
print("Function error: \(error?.localizedDescription ?? "Unknown")")
return
}
print("Success: \(result?.data ?? "")")
}
}If you want to allow unauthenticated access temporarily (development only), sign users in anonymously:
Web/JavaScript:
import { getAuth, signInAnonymously, onAuthStateChanged } from "firebase/auth";
import { getFirestore, collection, getDocs } from "firebase/firestore";
const auth = getAuth();
const db = getFirestore();
onAuthStateChanged(auth, async (user) => {
if (!user) {
// Sign in anonymously if not already signed in
try {
await signInAnonymously(auth);
} catch (error) {
console.error("Anonymous sign-in failed:", error);
}
} else {
// User is authenticated (anonymously or otherwise)
const querySnapshot = await getDocs(collection(db, "items"));
querySnapshot.forEach(doc => console.log(doc.data()));
}
});Security Rules for Anonymous Access (Development Only):
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Allow anonymous and authenticated users
match /{document=**} {
allow read, write: if request.auth != null;
}
}
}WARNING: Before deploying to production, switch back to authenticated-only rules and remove anonymous sign-in from production code.
Auth tokens expire after 1 hour. If operations fail after long periods, refresh the token:
Web/JavaScript:
import { getAuth } from "firebase/auth";
const auth = getAuth();
// Force token refresh
const user = auth.currentUser;
if (user) {
const refreshedToken = await user.getIdToken(true);
console.log("Token refreshed:", refreshedToken);
}
// Or let Firebase SDK handle it automatically
onAuthStateChanged(auth, async (user) => {
if (user) {
// Firebase automatically refreshes expired tokens
const token = await user.getIdToken();
}
});Check token validity:
const expirationTime = user.stsTokenManager.expirationTime;
const currentTime = new Date().getTime();
if (currentTime > expirationTime) {
console.log("Token expired, refreshing...");
await user.getIdToken(true); // Force refresh
} else {
console.log("Token is still valid");
}Admin SDK automatically handles token refresh:
const admin = require("firebase-admin");
// No need to manage tokens with Admin SDK
const doc = await admin.firestore().collection("users").doc("userId").get();When using Firebase Emulator Suite, UNAUTHENTICATED errors often indicate misconfigured emulator connections. Ensure both Auth and Functions emulators are running and the environment variables FIREBASE_AUTH_EMULATOR_HOST and FIREBASE_DATABASE_EMULATOR_HOST are set correctly. Platform-specific issues: iOS/macOS users may encounter UNAUTHENTICATED even with valid tokens due to SDK issues—ensure you're using the latest Firebase SDK versions. Flutter developers using App Check should verify App Check tokens are valid before calling functions. The UNAUTHENTICATED error differs from PERMISSION_DENIED: UNAUTHENTICATED means "no valid credentials" while PERMISSION_DENIED means "authenticated but access denied by rules". Always check error.code in your catch blocks to handle these differently. Service Accounts used by Admin SDK bypass auth entirely—only client SDKs (web, mobile) need authentication.
Callable Functions: INTERNAL - Unhandled exception
How to fix "Callable Functions: INTERNAL - Unhandled exception" in Firebase
auth/invalid-hash-algorithm: Hash algorithm doesn't match supported options
How to fix "auth/invalid-hash-algorithm: Hash algorithm doesn't match supported options" in Firebase
Hosting: CORS configuration not set up properly
How to fix CORS configuration in Firebase Hosting
auth/reserved-claims: Custom claims use reserved OIDC claim names
How to fix "reserved claims" error when setting custom claims in Firebase
Callable Functions: UNAUTHENTICATED - Invalid credentials
How to fix "UNAUTHENTICATED - Invalid credentials" in Firebase Callable Functions