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

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, os passa de volta para um dispositivo cliente e, em seguida, 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 do seu servidor pode ser usado por um dispositivo cliente para autenticar com o Firebase ( iOS+ , Android , web ). Depois de autenticada, essa identidade será usada para 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 do Realtime Database e no objeto request.auth em suas Regras de segurança do Cloud Storage .

Você pode criar um token personalizado com o SDK Admin do Firebase ou usar uma biblioteca JWT de terceiros se o 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 SDK Admin do Firebase 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. Cuidado especial deve ser tomado para garantir que o arquivo JSON da conta de serviço não seja exposto a terceiros.
  • Permitir que o SDK Admin descubra uma conta de serviço : esse método pode ser usado em ambientes gerenciados pelo Google, como Google Cloud Functions e App Engine. Talvez seja 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 talvez seja 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 de 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 SDK Admin 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 de conta de serviço é uma informação confidencial e deve-se ter 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 SDK Admin descubra uma conta de serviço

Se seu código for implantado em um ambiente gerenciado pelo Google, o SDK Admin poderá 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 SDK Admin poderá 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 provisionada 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 SDK Admin do Firebase poderá 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 do 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 SDK Admin do Firebase precisar descobrir uma string de ID de conta de serviço, ele fará isso 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 com 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 do token personalizado funcione. Talvez seja necessário usar o IAM e a seção de administração do Console do Google Cloud para conceder as permissões necessárias às contas de serviço padrão. 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 ao executar 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 de conta de serviço baixado. IDs de conta de serviço são endereços de e-mail que têm 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",
});

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 SDK Admin do Firebase deve invocar um serviço remoto. Além disso, você também deve verificar se a conta de serviço que o SDK Admin está usando para fazer essa chamada — geralmente {project-name}@appspot.gserviceaccount.com — tem 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 SDK Admin do Firebase

O SDK Admin do Firebase 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 especificar declarações adicionais a serem incluídas no token personalizado. Por exemplo, abaixo, um campo premiumAccount foi adicionado ao token personalizado, 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 tokens 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 autentica com o token personalizado chamando signInWithCustomToken() :

iOS+

Objetivo-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, será criado um registro para esse usuário.

Da mesma forma que com outros métodos de login (como signInWithEmailAndPassword() e signInWithCredential() ), o objeto auth em suas regras do Realtime Database e o objeto request.auth em suas 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 fora do 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 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 O endereço de e-mail da conta de serviço do seu projeto
sub Sujeito O 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 no momento A hora atual, em segundos desde a época do UNIX
exp Data de validade O tempo, em segundos desde a época do UNIX, em que o token expira. Pode ser no máximo 3600 segundos depois do iat .
Observação: isso controla apenas o tempo em que o próprio token personalizado expira. Mas assim que você conectar um usuário usando signInWithCustomToken() , ele permanecerá conectado ao dispositivo até que sua sessão seja invalidada ou o usuário saia.
uid O identificador exclusivo do usuário conectado deve ser uma string, entre 1 e 36 caracteres
claims (opcional) Declarações personalizadas opcionais para incluir nas variáveis auth / request.auth das regras de segurança

Veja alguns exemplos de implementações de como criar tokens personalizados em várias linguagens que o SDK Admin do Firebase não oferece suporte:

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 aplicativo cliente para ser usado 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 do IAM não ativada

Se você estiver especificando um ID de conta de serviço para assinar tokens, 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 SDK Admin do Firebase usa a API IAM para assinar tokens. Este 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 habilitá-lo para seu projeto.

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

Se a conta de serviço que o SDK Admin do Firebase estiver executando não tiver a permissão iam.serviceAccounts.signBlob , você poderá receber uma mensagem de erro como esta:

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 o papel do IAM "Criador de token de conta de serviço" à conta de serviço em questão, geralmente {project-name}@appspot.gserviceaccount.com :

  1. Abra o IAM e a página de administração 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 do papel.

Consulte a documentação do IAM para obter mais detalhes sobre esse processo ou saiba como atualizar papéis 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 SDK Admin do Firebase 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 confiando no 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.