Catch up on everything announced at Firebase Summit, and learn how Firebase can help you accelerate app development and run your app with confidence. Learn More

Crear fichas personalizadas

Organiza tus páginas con colecciones Guarda y categoriza el contenido según tus preferencias.

Firebase le brinda control total sobre la autenticación al permitirle autenticar usuarios o dispositivos mediante tokens web JSON (JWT) seguros. Usted genera estos tokens en su servidor, los pasa de vuelta a un dispositivo cliente y luego los usa para autenticarse a través del método signInWithCustomToken() .

Para lograr esto, debe crear un extremo de servidor que acepte credenciales de inicio de sesión, como un nombre de usuario y una contraseña, y, si las credenciales son válidas, devuelva un JWT personalizado. El JWT personalizado devuelto por su servidor puede ser utilizado por un dispositivo cliente para autenticarse con Firebase ( iOS+ , Android , web ). Una vez autenticada, esta identidad se utilizará al acceder a otros servicios de Firebase, como Firebase Realtime Database y Cloud Storage. Además, el contenido del JWT estará disponible en el objeto auth en sus reglas de base de datos en tiempo real y el objeto request.auth en sus reglas de seguridad de almacenamiento en la nube .

Puede crear un token personalizado con Firebase Admin SDK o puede usar una biblioteca JWT de terceros si su servidor está escrito en un idioma que Firebase no admite de forma nativa.

Antes de que empieces

Los tokens personalizados son JWT firmados donde la clave privada utilizada para firmar pertenece a una cuenta de servicio de Google. Hay varias formas de especificar la cuenta de servicio de Google que debe usar el SDK de administrador de Firebase para firmar tokens personalizados:

  • Usar un archivo JSON de cuenta de servicio : este método se puede usar en cualquier entorno, pero requiere que empaquetes un archivo JSON de cuenta de servicio junto con tu código. Se debe tener especial cuidado para garantizar que el archivo JSON de la cuenta de servicio no esté expuesto a terceros.
  • Permitir que Admin SDK descubra una cuenta de servicio : este método se puede usar en entornos administrados por Google, como Google Cloud Functions y App Engine. Es posible que deba configurar algunos permisos adicionales a través de Google Cloud Console.
  • Usar una ID de cuenta de servicio : cuando se usa en un entorno administrado por Google, este método firmará tokens usando la clave de la cuenta de servicio especificada. Sin embargo, utiliza un servicio web remoto y es posible que deba configurar permisos adicionales para esta cuenta de servicio a través de Google Cloud Console.

Usar un archivo JSON de cuenta de servicio

Los archivos JSON de la cuenta de servicio contienen toda la información correspondiente a las cuentas de servicio (incluida la clave privada RSA). Se pueden descargar desde la consola de Firebase. Siga las instrucciones de configuración del SDK de administrador para obtener más información sobre cómo inicializar el SDK de administrador con un archivo JSON de cuenta de servicio.

Este método de inicialización es adecuado para una amplia variedad de implementaciones de Admin SDK. También permite que Admin SDK cree y firme tokens personalizados localmente, sin realizar ninguna llamada remota a la API. El principal inconveniente de este enfoque es que requiere que empaquetes un archivo JSON de cuenta de servicio junto con tu código. También tenga en cuenta que la clave privada en un archivo JSON de cuenta de servicio es información confidencial y se debe tener especial cuidado para mantenerla confidencial. Específicamente, absténgase de agregar archivos JSON de cuentas de servicio al control de versiones públicas.

Permitir que Admin SDK descubra una cuenta de servicio

Si su código se implementa en un entorno administrado por Google, el SDK de administrador puede intentar descubrir automáticamente un medio para firmar tokens personalizados:

  • Si su código se implementa en el entorno estándar de App Engine para Java, Python o Go, el SDK de administrador puede usar el servicio App Identity presente en ese entorno para firmar tokens personalizados. El servicio App Identity firma datos mediante una cuenta de servicio proporcionada para su aplicación por Google App Engine.

  • Si su código se implementa en algún otro entorno administrado (p. ej., Google Cloud Functions, Google Compute Engine), el SDK de administrador de Firebase puede detectar automáticamente una cadena de ID de cuenta de servicio del servidor de metadatos local. El ID de cuenta de servicio descubierto se usa luego junto con el servicio IAM para firmar tokens de forma remota.

Para utilizar estos métodos de firma, inicialice el SDK con las credenciales predeterminadas de la aplicación de Google y no especifique una cadena de ID de cuenta de servicio:

Nodo.js

initializeApp();

Java

FirebaseApp.initializeApp();

Pitón

default_app = firebase_admin.initialize_app()

Vamos

app, err := firebase.NewApp(context.Background(), nil)
if err != nil {
	log.Fatalf("error initializing app: %v\n", err)
}

C#

FirebaseApp.Create();

Para probar el mismo código localmente, descargue un archivo JSON de cuenta de servicio y configure la variable de entorno GOOGLE_APPLICATION_CREDENTIALS para que apunte a él.

Si Firebase Admin SDK tiene que descubrir una cadena de ID de cuenta de servicio, lo hace cuando su código crea un token personalizado por primera vez. El resultado se almacena en caché y se reutiliza para operaciones posteriores de firma de tokens. El ID de cuenta de servicio descubierto automáticamente suele ser una de las cuentas de servicio predeterminadas proporcionadas por Google Cloud:

Al igual que con los ID de cuentas de servicio especificados explícitamente, los ID de cuentas de servicio descubiertos automáticamente deben tener el permiso iam.serviceAccounts.signBlob para que funcione la creación de tokens personalizados. Es posible que deba usar la sección IAM y administración de Google Cloud Console para otorgar los permisos necesarios a las cuentas de servicio predeterminadas. Consulte la sección de solución de problemas a continuación para obtener más detalles.

Usar una ID de cuenta de servicio

Para mantener la coherencia entre varias partes de su aplicación, puede especificar un ID de cuenta de servicio cuyas claves se utilizarán para firmar tokens cuando se ejecute en un entorno administrado por Google. Esto puede hacer que las políticas de IAM sean más simples y seguras, y evitar tener que incluir el archivo JSON de la cuenta de servicio en su código.

El ID de la cuenta de servicio se puede encontrar en Google Cloud Console o en el campo client_email de un archivo JSON de cuenta de servicio descargado. Los ID de cuenta de servicio son direcciones de correo electrónico que tienen el siguiente formato: <client-id>@<project-id>.iam.gserviceaccount.com . Identifican de forma única las cuentas de servicio en los proyectos de Firebase y Google Cloud.

Para crear tokens personalizados con un ID de cuenta de servicio independiente, inicialice el SDK como se muestra a continuación:

Nodo.js

initializeApp({
  serviceAccountId: 'my-client-id@my-project-id.iam.gserviceaccount.com',
});

Java

FirebaseOptions options = FirebaseOptions.builder()
    .setCredentials(GoogleCredentials.getApplicationDefault())
    .setServiceAccountId("my-client-id@my-project-id.iam.gserviceaccount.com")
    .build();
FirebaseApp.initializeApp(options);

Pitón

options = {
    'serviceAccountId': 'my-client-id@my-project-id.iam.gserviceaccount.com',
}
firebase_admin.initialize_app(options=options)

Vamos

conf := &firebase.Config{
	ServiceAccountID: "my-client-id@my-project-id.iam.gserviceaccount.com",
}
app, err := firebase.NewApp(context.Background(), conf)
if err != nil {
	log.Fatalf("error initializing app: %v\n", err)
}

C#

FirebaseApp.Create(new AppOptions()
{
    Credential = GoogleCredential.GetApplicationDefault(),
    ServiceAccountId = "my-client-id@my-project-id.iam.gserviceaccount.com",
});

Los ID de cuentas de servicio no son información confidencial y, por lo tanto, su exposición es intrascendente. Sin embargo, para firmar tokens personalizados con la cuenta de servicio especificada, el SDK de Firebase Admin debe invocar un servicio remoto. Además, también debe asegurarse de que la cuenta de servicio que usa Admin SDK para realizar esta llamada, {project-name}@appspot.gserviceaccount.com , tenga el permiso iam.serviceAccounts.signBlob . Consulte la sección de solución de problemas a continuación para obtener más detalles.

Crea tokens personalizados con el SDK de administración de Firebase

El SDK de Firebase Admin tiene un método integrado para crear tokens personalizados. Como mínimo, debe proporcionar un uid , que puede ser cualquier cadena, pero debe identificar de forma única al usuario o dispositivo que está autenticando. Estos tokens caducan después de una hora.

Nodo.js

const uid = 'some-uid';

getAuth()
  .createCustomToken(uid)
  .then((customToken) => {
    // Send token back to client
  })
  .catch((error) => {
    console.log('Error creating custom token:', error);
  });

Java

String uid = "some-uid";

String customToken = FirebaseAuth.getInstance().createCustomToken(uid);
// Send token back to client

Pitón

uid = 'some-uid'

custom_token = auth.create_custom_token(uid)

Vamos

client, err := app.Auth(context.Background())
if err != nil {
	log.Fatalf("error getting Auth client: %v\n", err)
}

token, err := client.CustomToken(ctx, "some-uid")
if err != nil {
	log.Fatalf("error minting custom token: %v\n", err)
}

log.Printf("Got custom token: %v\n", token)

C#

var uid = "some-uid";

string customToken = await FirebaseAuth.DefaultInstance.CreateCustomTokenAsync(uid);
// Send token back to client

Opcionalmente, también puede especificar reclamos adicionales para que se incluyan en el token personalizado. Por ejemplo, a continuación, se agregó un campo premiumAccount al token personalizado, que estará disponible en los objetos auth / request.auth en sus Reglas de seguridad:

Nodo.js

const userId = 'some-uid';
const additionalClaims = {
  premiumAccount: true,
};

getAuth()
  .createCustomToken(userId, additionalClaims)
  .then((customToken) => {
    // Send token back to client
  })
  .catch((error) => {
    console.log('Error creating custom token:', error);
  });

Java

String uid = "some-uid";
Map<String, Object> additionalClaims = new HashMap<String, Object>();
additionalClaims.put("premiumAccount", true);

String customToken = FirebaseAuth.getInstance()
    .createCustomToken(uid, additionalClaims);
// Send token back to client

Pitón

uid = 'some-uid'
additional_claims = {
    'premiumAccount': True
}

custom_token = auth.create_custom_token(uid, additional_claims)

Vamos

client, err := app.Auth(context.Background())
if err != nil {
	log.Fatalf("error getting Auth client: %v\n", err)
}

claims := map[string]interface{}{
	"premiumAccount": true,
}

token, err := client.CustomTokenWithClaims(ctx, "some-uid", claims)
if err != nil {
	log.Fatalf("error minting custom token: %v\n", err)
}

log.Printf("Got custom token: %v\n", token)

C#

var uid = "some-uid";
var additionalClaims = new Dictionary<string, object>()
{
    { "premiumAccount", true },
};

string customToken = await FirebaseAuth.DefaultInstance
    .CreateCustomTokenAsync(uid, additionalClaims);
// Send token back to client

Nombres de token personalizados reservados

Inicie sesión con tokens personalizados en los clientes

Después de crear un token personalizado, debe enviarlo a su aplicación cliente. La aplicación cliente se autentica con el token personalizado llamando a signInWithCustomToken() :

iOS+

C objetivo
[[FIRAuth auth] signInWithCustomToken:customToken
                           completion:^(FIRAuthDataResult * _Nullable authResult,
                                        NSError * _Nullable error) {
  // ...
}];
Rápido
Auth.auth().signIn(withCustomToken: customToken ?? "") { user, error in
  // ...
}

Androide

mAuth.signInWithCustomToken(mCustomToken)
        .addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
            @Override
            public void onComplete(@NonNull Task<AuthResult> task) {
                if (task.isSuccessful()) {
                    // Sign in success, update UI with the signed-in user's information
                    Log.d(TAG, "signInWithCustomToken:success");
                    FirebaseUser user = mAuth.getCurrentUser();
                    updateUI(user);
                } else {
                    // If sign in fails, display a message to the user.
                    Log.w(TAG, "signInWithCustomToken:failure", task.getException());
                    Toast.makeText(CustomAuthActivity.this, "Authentication failed.",
                            Toast.LENGTH_SHORT).show();
                    updateUI(null);
                }
            }
        });

Unidad

auth.SignInWithCustomTokenAsync(custom_token).ContinueWith(task => {
  if (task.IsCanceled) {
    Debug.LogError("SignInWithCustomTokenAsync was canceled.");
    return;
  }
  if (task.IsFaulted) {
    Debug.LogError("SignInWithCustomTokenAsync encountered an error: " + task.Exception);
    return;
  }

  Firebase.Auth.FirebaseUser newUser = task.Result;
  Debug.LogFormat("User signed in successfully: {0} ({1})",
      newUser.DisplayName, newUser.UserId);
});

C++

firebase::Future<firebase::auth::User*> result =
    auth->SignInWithCustomToken(custom_token);

Web version 8

firebase.auth().signInWithCustomToken(token)
  .then((userCredential) => {
    // Signed in
    var user = userCredential.user;
    // ...
  })
  .catch((error) => {
    var errorCode = error.code;
    var errorMessage = error.message;
    // ...
  });

Web version 9

import { getAuth, signInWithCustomToken } from "firebase/auth";

const auth = getAuth();
signInWithCustomToken(auth, token)
  .then((userCredential) => {
    // Signed in
    const user = userCredential.user;
    // ...
  })
  .catch((error) => {
    const errorCode = error.code;
    const errorMessage = error.message;
    // ...
  });

Si la autenticación tiene éxito, su usuario ahora iniciará sesión en su aplicación cliente con la cuenta especificada por el uid incluido en el token personalizado. Si esa cuenta no existía previamente, se creará un registro para ese usuario.

De la misma manera que con otros métodos de inicio de sesión (como signInWithEmailAndPassword() y signInWithCredential() ), el objeto auth en sus Reglas de base de datos en tiempo real y el objeto request.auth en sus Reglas de seguridad de Cloud Storage se completarán con el uid del usuario. En este caso, el uid será el que especificó al generar el token personalizado.

Reglas de la base de datos

{
  "rules": {
    "adminContent": {
      ".read": "auth.uid === 'some-uid'"
    }
  }
}

Reglas de almacenamiento

service firebase.storage {
  match /b/<your-firebase-storage-bucket>/o {
    match /adminContent/{filename} {
      allow read, write: if request.auth != null && request.auth.uid == "some-uid";
    }
  }
}

Si el token personalizado contiene reclamos adicionales, se puede hacer referencia a ellos fuera del auth.token (Firebase Realtime Database) o request.auth.token (Cloud Storage) en sus reglas:

Reglas de la base de datos

{
  "rules": {
    "premiumContent": {
      ".read": "auth.token.premiumAccount === true"
    }
  }
}

Reglas de almacenamiento

service firebase.storage {
  match /b/<your-firebase-storage-bucket>/o {
    match /premiumContent/{filename} {
      allow read, write: if request.auth.token.premiumAccount == true;
    }
  }
}

Cree tokens personalizados utilizando una biblioteca JWT de terceros

Si su backend está en un idioma que no tiene un SDK de administrador de Firebase oficial, aún puede crear manualmente tokens personalizados. Primero, busque una biblioteca JWT de terceros para su idioma. Luego, use esa biblioteca JWT para crear un JWT que incluya las siguientes afirmaciones:

Reclamos de tokens personalizados
alg Algoritmo "RS256"
iss Editor La dirección de correo electrónico de la cuenta de servicio de tu proyecto
sub Tema La dirección de correo electrónico de la cuenta de servicio de tu proyecto
aud Audiencia "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit"
iat Emitido a tiempo La hora actual, en segundos desde la época de UNIX
exp Tiempo de expiración La hora, en segundos desde la época de UNIX, en la que caduca el token. Puede ser un máximo de 3600 segundos más tarde que el iat .
Nota: esto solo controla el momento en que caduca el token personalizado . Pero una vez que inicia la sesión de un usuario mediante signInWithCustomToken() , permanecerá conectado al dispositivo hasta que se invalide su sesión o hasta que el usuario cierre la sesión.
uid El identificador único del usuario que inició sesión debe ser una cadena de entre 1 y 36 caracteres
claims (opcional) Reclamaciones personalizadas opcionales para incluir en las reglas de seguridad auth / request.auth variables

Aquí hay algunas implementaciones de ejemplo de cómo crear tokens personalizados en una variedad de idiomas que Firebase Admin SDK no admite:

PHP

Usando php-jwt :

// Requires: composer require firebase/php-jwt
use Firebase\JWT\JWT;

// Get your service account's email address and private key from the JSON key file
$service_account_email = "abc-123@a-b-c-123.iam.gserviceaccount.com";
$private_key = "-----BEGIN PRIVATE KEY-----...";

function create_custom_token($uid, $is_premium_account) {
  global $service_account_email, $private_key;

  $now_seconds = time();
  $payload = array(
    "iss" => $service_account_email,
    "sub" => $service_account_email,
    "aud" => "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit",
    "iat" => $now_seconds,
    "exp" => $now_seconds+(60*60),  // Maximum expiration time is one hour
    "uid" => $uid,
    "claims" => array(
      "premium_account" => $is_premium_account
    )
  );
  return JWT::encode($payload, $private_key, "RS256");
}

Rubí

Usando ruby-jwt :

require "jwt"

# Get your service account's email address and private key from the JSON key file
$service_account_email = "service-account@my-project-abc123.iam.gserviceaccount.com"
$private_key = OpenSSL::PKey::RSA.new "-----BEGIN PRIVATE KEY-----\n..."

def create_custom_token(uid, is_premium_account)
  now_seconds = Time.now.to_i
  payload = {:iss => $service_account_email,
             :sub => $service_account_email,
             :aud => "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit",
             :iat => now_seconds,
             :exp => now_seconds+(60*60), # Maximum expiration time is one hour
             :uid => uid,
             :claims => {:premium_account => is_premium_account}}
  JWT.encode payload, $private_key, "RS256"
end

Después de crear el token personalizado, envíelo a su aplicación cliente para usarlo para autenticarse con Firebase. Consulte los ejemplos de código anteriores para saber cómo hacerlo.

Solución de problemas

Esta sección describe algunos problemas comunes que los desarrolladores pueden encontrar al crear tokens personalizados y cómo resolverlos.

API de IAM no habilitada

Si está especificando una ID de cuenta de servicio para firmar tokens, es posible que obtenga un error similar al siguiente:

Identity and Access Management (IAM) API has not been used in project
1234567890 before or it is disabled. Enable it by visiting
https://console.developers.google.com/apis/api/iam.googleapis.com/overview?project=1234567890
then retry. If you enabled this API recently, wait a few minutes for the action
to propagate to our systems and retry.

El SDK de Firebase Admin usa la API de IAM para firmar tokens. Este error indica que la API de IAM no está habilitada actualmente para su proyecto de Firebase. Abra el enlace en el mensaje de error en un navegador web y haga clic en el botón "Habilitar API" para habilitarlo para su proyecto.

La cuenta de servicio no tiene los permisos requeridos

Si la cuenta de servicio con la que se ejecuta Firebase Admin SDK no tiene el permiso iam.serviceAccounts.signBlob , es posible que reciba un mensaje de error como el siguiente:

Permission iam.serviceAccounts.signBlob is required to perform this operation
on service account projects/-/serviceAccounts/{your-service-account-id}.

La forma más fácil de resolver esto es otorgar el rol de IAM "Creador de token de cuenta de servicio" a la cuenta de servicio en cuestión, generalmente {project-name}@appspot.gserviceaccount.com :

  1. Abra la página de administración e IAM en Google Cloud Console.
  2. Seleccione su proyecto y haga clic en "Continuar".
  3. Haga clic en el icono de edición correspondiente a la cuenta de servicio que desea actualizar.
  4. Haga clic en "Agregar otro rol".
  5. Escriba "Creador de token de cuenta de servicio" en el filtro de búsqueda y selecciónelo de los resultados.
  6. Haga clic en "Guardar" para confirmar la concesión del rol.

Consulte la documentación de IAM para obtener más detalles sobre este proceso o aprenda a actualizar roles con las herramientas de línea de comandos de gcloud.

No se pudo determinar la cuenta de servicio

Si recibe un mensaje de error similar al siguiente, Firebase Admin SDK no se ha inicializado correctamente.

Failed to determine service account ID. Initialize the SDK with service account
credentials or specify a service account ID with iam.serviceAccounts.signBlob
permission.

Si confía en el SDK para detectar automáticamente un ID de cuenta de servicio, asegúrese de que el código se implemente en un entorno administrado de Google con un servidor de metadatos. De lo contrario, asegúrese de especificar el archivo JSON de la cuenta de servicio o el ID de la cuenta de servicio en la inicialización del SDK.