Using Firebase Auth claims with Swift, Kotlin and JavaScript

Firebase Authentication supports built-in and custom user claims that allow us to conditionally expose functionality to users based on authorization groups. This post demonstrates the syntax to add custom claims in a Firebase backend, and read claims from mobile apps.

What are Claims?

In identity systems, a "Claim" is is a piece of metadata about a user's identity. They are a lot like a "Tag", in that claims are usually an array of strings attached to a user's account. What they mean is up to implementation--they could signal anything.

Usually, though, a claim is used to authorize a user to some specific functionality within the application. For example, a user claim could be "administrator", and an application could check if a user has the "administrator" claim before allowing that user to access an admin section of a navigation system.

Firebase Claims

Like many identity systems, Firebase has some claims built-in, and allows application developers to add custom claims to the user's identity (i.e. profile). Firebase has a limit of 1000 bytes for custom claim storage, so custom claims isn't intended as a repository for a full user profile -- Firebase Cloud Firestore is a better place to store extensive user metadata.

Claims can be added via the Firebase admin SDK, and can be read by any of the client SDKs. Below are code examples for Swift, Kotlin and JavaScript.

Adding a Custom Claim

How can you add a custom claim that applications or cloud functions can read? I typically use a Firebase cloud function, which encapsulates this security operation on the backend side, allowing the function to use the Firebase Admin SDK.

 1// Call this function POST function with payload { email: ''} while signed in to a Firebase Auth account
 2exports.addSysAdmin = functions.https.onCall(async (data, context) => {
 3  // Only current administrators can create new administrators
 4  if (context.auth.token.administrator == false) {
 5    throw new functions.https.HttpsError('permission-denied', 'Must be an admin to use this endpoint')
 6  }
 8  const email =;
 9  const user = await admin.auth().getUserByEmail(email)
11  if (user == null) {
12    throw new functions.https.HttpsError('invalid-argument', `No user associated with email ${email}`);
13  }
15  const customClaims = user.customClaims || {}
16  customClaims.administrator = true
17  admin.auth().setCustomUserClaims(user.uid, customClaims)
19  return {
20    success: true,
21    claims: customClaims,
22    message: null
23  } 

Using Custom Claims in Applications

Once custom claims have been added to user accounts, applications can easily read claims to check whether users have access to some set of functionality. Below are examples in Swift, Kotlin and JavaScript. In these examples we use the claim "administrator" to authorize users to some administrator functionality within an application.


To fetch a user's claims on the client in Swift, the user must first be authenticated. Once authenticated the claims can be fetched asynchronously.

 1// Service function
 2func isUserAdministrator() async -> Result<Bool, String> {
 3    // Check if the user is authenticated.
 4    guard let user = Auth.auth().currentUser else {
 5        return .failure("Not signed in")
 6    }
 8    do {
 9        let tokenResult = try await user.getIDTokenResult()
10        let claims =
11        let isAdmin = claims["administrator"] as? Bool ?? false
12        return .success(isAdmin) 
13    } catch (let error) {
14      return .failure(error.localizedDescription)
15    }

To call the service function:

 1switch result {
 2  let result = await isUserAdministrator()
 4  switch result {
 5    case .success(let isAdmin):
 6      print("User is an administrator? \(isAdmin)")
 7    case .failure(let error):
 8      print("Error checking claims", error)
 9  }


Kotlin syntax to check the claim is similar:

 1sealed class Result<out Success, out Failure>
 2data class Success<out Success>(val value: Success) : Result<Success, Nothing>()
 3data class Failure<out Failure>(val reason: Failure) : Result<Nothing, Failure>()
 5suspend fun isUserAdministrator() : Result<Boolean, Exception> {
 6  return try {
 7    val currentUser = auth.currentUser ?: throw Exception("Not signed in")
 9    val tokenResult = currentUser.getIdToken(false).await()
10    val claims =
11    val isAdmin = claims["administrator"] as Boolean? ?: false
12    Success(isAdmin)
13  } catch (e: Exception) {
14    Failure(e)
15  }

To call the service function:

1when (val result = isUserAdministrator()) {
2    is Success -> print("User is an administrator? ${result.value}")
3    is Failure -> print(result.reason.localizedMessage)


To evaluate whether a user calling a Firebase cloud function is an administrator, use the context object. Since this is a backend function, we'll throw an HTTP error if the user isn't authorized.

1exports.somePriviligedFunction = functions.https.onCall(async (data, context) => {
2  if (context.auth.token.administrator == false) {
3    	throw new functions.https.HttpsError('permission-denied', 'Must be an admin to use this endpoint)
4  }
5  // Continue to execute the functionality protected by the "administrator" claim