Acompanhe as novidades sobre tudo o que foi anunciado no Firebase Summit e saiba como o Firebase pode ajudar a acelerar o desenvolvimento de apps e executá-los com confiança. Saiba mais

Criar tokens personalizados

Mantenha tudo organizado com as coleções Salve e categorize o conteúdo com base nas suas preferências.

O Firebase oferece controle total sobre a autenticação, permitindo que você autentique usuários ou dispositivos usando JSON Web Tokens (JWTs) seguros. Você gera esses tokens em seu servidor, passa-os de volta para um dispositivo cliente e os usa para autenticar por meio do método signInWithCustomToken() .

Para conseguir isso, você deve criar um endpoint de servidor que aceite credenciais de login, como nome de usuário e senha, e, se as credenciais forem válidas, retorne um JWT personalizado. O JWT personalizado retornado de seu servidor pode ser usado por um dispositivo cliente para autenticação com Firebase ( iOS+ , Android , web ). Depois de autenticada, essa identidade será usada ao acessar outros serviços do Firebase, como o Firebase Realtime Database e o Cloud Storage. Além disso, o conteúdo do JWT estará disponível no objeto auth em suas regras de banco de dados em tempo real e no objeto request.auth em suas regras de segurança de armazenamento em nuvem .

Você pode criar um token personalizado com o Firebase Admin SDK ou pode usar uma biblioteca JWT de terceiros se seu servidor for escrito em uma linguagem que o Firebase não oferece suporte nativo.

Antes de você começar

Os tokens personalizados são JWTs assinados em que a chave privada usada para assinatura pertence a uma conta de serviço do Google. Há várias maneiras de especificar a conta de serviço do Google que deve ser usada pelo Firebase Admin SDK para assinar tokens personalizados:

  • Usando um arquivo JSON de conta de serviço -- esse método pode ser usado em qualquer ambiente, mas exige que você empacote um arquivo JSON de conta de serviço junto com seu código. Deve-se tomar cuidado especial para garantir que o arquivo JSON da conta de serviço não seja exposto a terceiros.
  • Permitir que o Admin SDK descubra uma conta de serviço -- esse método pode ser usado em ambientes gerenciados pelo Google, como o Google Cloud Functions e o App Engine. Pode ser necessário configurar algumas permissões adicionais por meio do Console do Google Cloud.
  • Usando um ID de conta de serviço -- quando usado em um ambiente gerenciado pelo Google, esse método assinará tokens usando a chave da conta de serviço especificada. No entanto, ele usa um serviço da Web remoto e pode ser necessário configurar permissões adicionais para essa conta de serviço por meio do Console do Google Cloud.

Como usar um arquivo JSON de conta de serviço

Os arquivos JSON da conta de serviço contêm todas as informações correspondentes às contas de serviço (incluindo a chave privada RSA). Eles podem ser baixados do console do Firebase. Siga as instruções de configuração do Admin SDK para obter mais informações sobre como inicializar o Admin SDK com um arquivo JSON da conta de serviço.

Esse método de inicialização é adequado para uma ampla variedade de implantações do Admin SDK. Além disso, permite que o Admin SDK crie e assine tokens personalizados localmente, sem fazer chamadas de API remotas. A principal desvantagem dessa abordagem é que ela exige que você empacote um arquivo JSON de conta de serviço junto com seu código. Observe também que a chave privada em um arquivo JSON da conta de serviço é uma informação confidencial e deve-se tomar cuidado especial para mantê-la confidencial. Especificamente, evite adicionar arquivos JSON da conta de serviço ao controle de versão pública.

Permitir que o Admin SDK descubra uma conta de serviço

Se seu código for implantado em um ambiente gerenciado pelo Google, o Admin SDK pode tentar descobrir automaticamente um meio de assinar tokens personalizados:

  • Se seu código for implantado no ambiente padrão do App Engine para Java, Python ou Go, o Admin SDK pode usar o serviço App Identity presente nesse ambiente para assinar tokens personalizados. O serviço App Identity assina dados usando uma conta de serviço fornecida para seu aplicativo pelo Google App Engine.

  • Se seu código for implantado em algum outro ambiente gerenciado (por exemplo, Google Cloud Functions, Google Compute Engine), o Firebase Admin SDK pode descobrir automaticamente uma string de ID de conta de serviço do servidor de metadados local . O ID da conta de serviço descoberta é usado em conjunto com o serviço IAM para assinar tokens remotamente.

Para usar esses métodos de assinatura, inicialize o SDK com as credenciais do Google Application Default e não especifique uma string de ID de conta de serviço:

Node.js

initializeApp();

Java

FirebaseApp.initializeApp();

Pitão

default_app = firebase_admin.initialize_app()

Vai

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

C #

FirebaseApp.Create();

Para testar o mesmo código localmente, baixe um arquivo JSON da conta de serviço e defina a variável de ambiente GOOGLE_APPLICATION_CREDENTIALS para apontar para ele.

Se o Firebase Admin SDK precisar descobrir uma string de ID de conta de serviço, ele o fará quando seu código criar um token personalizado pela primeira vez. O resultado é armazenado em cache e reutilizado para operações de assinatura de token subsequentes. O ID da conta de serviço descoberta automaticamente geralmente é uma das contas de serviço padrão fornecidas pelo Google Cloud:

Assim como os IDs de conta de serviço especificados explicitamente, os IDs de conta de serviço descobertos automaticamente devem ter a permissão iam.serviceAccounts.signBlob para que a criação de token personalizado funcione. Talvez seja necessário usar a seção IAM e administrador do Google Cloud Console para conceder às contas de serviço padrão as permissões necessárias. Consulte a seção de solução de problemas abaixo para obter mais detalhes.

Como usar um ID de conta de serviço

Para manter a consistência entre várias partes do seu aplicativo, você pode especificar um ID de conta de serviço cujas chaves serão usadas para assinar tokens durante a execução em um ambiente gerenciado pelo Google. Isso pode tornar as políticas do IAM mais simples e seguras e evitar a necessidade de incluir o arquivo JSON da conta de serviço em seu código.

O ID da conta de serviço pode ser encontrado no Console do Google Cloud ou no campo client_email de um arquivo JSON da conta de serviço baixado. IDs de conta de serviço são endereços de e-mail com o seguinte formato: <client-id>@<project-id>.iam.gserviceaccount.com . Eles identificam exclusivamente contas de serviço em projetos do Firebase e do Google Cloud.

Para criar tokens personalizados usando um ID de conta de serviço separado, inicialize o SDK conforme mostrado abaixo:

Node.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ão

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

Vai

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",
});

Os IDs de conta de serviço não são informações confidenciais e, portanto, sua exposição é irrelevante. No entanto, para assinar tokens personalizados com a conta de serviço especificada, o Firebase Admin SDK deve invocar um serviço remoto. Além disso, você também deve certificar-se de que a conta de serviço que o Admin SDK está usando para fazer essa chamada — geralmente {project-name}@appspot.gserviceaccount.com — tenha a permissão iam.serviceAccounts.signBlob . Consulte a seção de solução de problemas abaixo para obter mais detalhes.

Crie tokens personalizados usando o Firebase Admin SDK

O Firebase Admin SDK tem um método integrado para criar tokens personalizados. No mínimo, você precisa fornecer um uid , que pode ser qualquer string, mas deve identificar exclusivamente o usuário ou dispositivo que você está autenticando. Esses tokens expiram após uma hora.

Node.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ão

uid = 'some-uid'

custom_token = auth.create_custom_token(uid)

Vai

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

Você também pode, opcionalmente, especificar declarações adicionais a serem incluídas no token personalizado. Por exemplo, abaixo, foi adicionado um campo premiumAccount ao token customizado, que estará disponível nos objetos auth / request.auth em suas Regras de Segurança:

Node.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ão

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

custom_token = auth.create_custom_token(uid, additional_claims)

Vai

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

Nomes de token personalizados reservados

Faça login usando tokens personalizados em clientes

Depois de criar um token personalizado, você deve enviá-lo para seu aplicativo cliente. O aplicativo cliente é autenticado com o token personalizado chamando signInWithCustomToken() :

iOS+

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

Android

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);
                }
            }
        });

Unidade

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;
    // ...
  });

Se a autenticação for bem-sucedida, seu usuário estará conectado ao aplicativo cliente com a conta especificada pelo uid incluído no token personalizado. Se essa conta não existia anteriormente, um registro para esse usuário será criado.

Da mesma forma que com outros métodos de login (como signInWithEmailAndPassword() e signInWithCredential() ), o objeto auth nas regras do Realtime Database e o objeto request.auth nas regras de segurança do Cloud Storage serão preenchidos com o uid do usuário. Nesse caso, o uid será aquele que você especificou ao gerar o token personalizado.

Regras do banco de dados

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

Regras de Armazenamento

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";
    }
  }
}

Se o token personalizado contiver declarações adicionais, elas poderão ser referenciadas no auth.token (Firebase Realtime Database) ou request.auth.token (Cloud Storage) em suas regras:

Regras do banco de dados

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

Regras de armazenamento

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

Crie tokens personalizados usando uma biblioteca JWT de terceiros

Se seu back-end estiver em um idioma que não tenha um SDK Admin oficial do Firebase, você ainda poderá criar tokens personalizados manualmente. Primeiro, encontre uma biblioteca JWT de terceiros para o seu idioma. Em seguida, use essa biblioteca JWT para criar um JWT que inclua as seguintes declarações:

Reivindicações de token personalizado
alg Algoritmo "RS256"
iss Emissor Endereço de e-mail da conta de serviço do seu projeto
sub Sujeito Endereço de e-mail da conta de serviço do seu projeto
aud Público "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit"
iat Emitido na hora A hora atual, em segundos, desde a época do UNIX
exp Data de validade O tempo, em segundos desde a época do UNIX, no qual o token expira. Pode ser no máximo 3600 segundos depois do iat .
Observação: isso controla apenas a hora em que o próprio token personalizado expira. Porém, assim que você conectar um usuário usando signInWithCustomToken() , ele permanecerá conectado ao dispositivo até que a sessão seja invalidada ou o usuário saia.
uid O identificador exclusivo do usuário conectado deve ser uma string, entre 1 e 128 caracteres, inclusive. uid s mais curtos oferecem melhor desempenho.
claims (opcional) Declarações customizadas opcionais para incluir nas variáveis auth / request.auth das regras de segurança

Aqui estão alguns exemplos de implementações de como criar tokens personalizados em vários idiomas não compatíveis com o Firebase Admin SDK:

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");
}

Rubi

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

Depois de criar o token personalizado, envie-o ao seu aplicativo cliente para usar na autenticação com o Firebase. Consulte os exemplos de código acima para saber como fazer isso.

Solução de problemas

Esta seção descreve alguns problemas comuns que os desenvolvedores podem encontrar ao criar tokens personalizados e como resolvê-los.

API IAM não habilitada

Se você estiver especificando um ID de conta de serviço para tokens de assinatura, poderá receber um erro semelhante ao seguinte:

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.

O Firebase Admin SDK usa a API IAM para assinar tokens. Esse erro indica que a API do IAM não está ativada no momento para seu projeto do Firebase. Abra o link na mensagem de erro em um navegador da Web e clique no botão "Ativar API" para ativá-lo em seu projeto.

A conta de serviço não tem as permissões necessárias

Se a conta de serviço em que o Firebase Admin SDK está sendo executado não tiver a permissão iam.serviceAccounts.signBlob , você poderá receber uma mensagem de erro como a seguinte:

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

A maneira mais fácil de resolver isso é conceder a função IAM "Criador de token de conta de serviço" à conta de serviço em questão, geralmente {project-name}@appspot.gserviceaccount.com :

  1. Abra a página IAM e admin no Console do Google Cloud.
  2. Selecione seu projeto e clique em "Continuar".
  3. Clique no ícone de edição correspondente à conta de serviço que você deseja atualizar.
  4. Clique em "Adicionar outra função".
  5. Digite "Criador de token de conta de serviço" no filtro de pesquisa e selecione-o nos resultados.
  6. Clique em "Salvar" para confirmar a concessão da função.

Consulte a documentação do IAM para obter mais detalhes sobre esse processo ou saiba como atualizar funções usando as ferramentas de linha de comando gcloud.

Falha ao determinar a conta de serviço

Se você receber uma mensagem de erro semelhante à seguinte, o Firebase Admin SDK não foi inicializado corretamente.

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

Se você estiver contando com o SDK para descobrir automaticamente um ID de conta de serviço, certifique-se de que o código seja implantado em um ambiente gerenciado do Google com um servidor de metadados. Caso contrário, certifique-se de especificar o arquivo JSON da conta de serviço ou o ID da conta de serviço na inicialização do SDK.