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

Gerenciar sessões de usuário

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

As sessões do Firebase Authentication são de longa duração. Sempre que um usuário faz login, as credenciais do usuário são enviadas ao back-end do Firebase Authentication e trocadas por um token de ID do Firebase (um JWT) e um token de atualização. Os tokens de ID do Firebase têm vida curta e duram uma hora; o token de atualização pode ser usado para recuperar novos tokens de ID. Os tokens de atualização expiram apenas quando ocorre um dos seguintes:

  • O usuário é excluído
  • O usuário está desabilitado
  • Uma alteração importante na conta é detectada para o usuário. Isso inclui eventos como atualizações de senha ou endereço de e-mail.

O SDK Admin do Firebase oferece a capacidade de revogar tokens de atualização para um usuário especificado. Além disso, também é disponibilizada uma API para verificar a revogação do token de ID. Com esses recursos, você tem mais controle sobre as sessões do usuário. O SDK oferece a capacidade de adicionar restrições para evitar que as sessões sejam usadas em circunstâncias suspeitas, bem como um mecanismo de recuperação de possíveis roubos de token.

Revogar tokens de atualização

Você pode revogar o token de atualização existente de um usuário quando um usuário relatar um dispositivo perdido ou roubado. Da mesma forma, se você descobrir uma vulnerabilidade geral ou suspeitar de um vazamento em larga escala de tokens ativos, poderá usar a API listUsers para pesquisar todos os usuários e revogar seus tokens para o projeto especificado.

As redefinições de senha também revogam os tokens existentes de um usuário; no entanto, o back-end do Firebase Authentication processa a revogação automaticamente nesse caso. Na revogação, o usuário é desconectado e solicitado a se autenticar novamente.

Aqui está um exemplo de implementação que usa o SDK Admin para revogar o token de atualização de um determinado usuário. Para inicializar o SDK Admin, siga as instruções na página de configuração .

Node.js

// Revoke all refresh tokens for a specified user for whatever reason.
// Retrieve the timestamp of the revocation, in seconds since the epoch.
getAuth()
  .revokeRefreshTokens(uid)
  .then(() => {
    return getAuth().getUser(uid);
  })
  .then((userRecord) => {
    return new Date(userRecord.tokensValidAfterTime).getTime() / 1000;
  })
  .then((timestamp) => {
    console.log(`Tokens revoked at: ${timestamp}`);
  });

Java

FirebaseAuth.getInstance().revokeRefreshTokens(uid);
UserRecord user = FirebaseAuth.getInstance().getUser(uid);
// Convert to seconds as the auth_time in the token claims is in seconds too.
long revocationSecond = user.getTokensValidAfterTimestamp() / 1000;
System.out.println("Tokens revoked at: " + revocationSecond);

Pitão

# Revoke tokens on the backend.
auth.revoke_refresh_tokens(uid)
user = auth.get_user(uid)
# Convert to seconds as the auth_time in the token claims is in seconds.
revocation_second = user.tokens_valid_after_timestamp / 1000
print('Tokens revoked at: {0}'.format(revocation_second))

Vai

client, err := app.Auth(ctx)
if err != nil {
	log.Fatalf("error getting Auth client: %v\n", err)
}
if err := client.RevokeRefreshTokens(ctx, uid); err != nil {
	log.Fatalf("error revoking tokens for user: %v, %v\n", uid, err)
}
// accessing the user's TokenValidAfter
u, err := client.GetUser(ctx, uid)
if err != nil {
	log.Fatalf("error getting user %s: %v\n", uid, err)
}
timestamp := u.TokensValidAfterMillis / 1000
log.Printf("the refresh tokens were revoked at: %d (UTC seconds) ", timestamp)

C#

await FirebaseAuth.DefaultInstance.RevokeRefreshTokensAsync(uid);
var user = await FirebaseAuth.DefaultInstance.GetUserAsync(uid);
Console.WriteLine("Tokens revoked at: " + user.TokensValidAfterTimestamp);

Detectar revogação de token de ID

Como os tokens de ID do Firebase são JWTs sem estado, você pode determinar que um token foi revogado apenas solicitando o status do token do back-end do Firebase Authentication. Por esse motivo, realizar essa verificação em seu servidor é uma operação cara, exigindo uma viagem extra de ida e volta da rede. Você pode evitar fazer essa solicitação de rede configurando as regras de segurança do Firebase que verificam a revogação em vez de usar o SDK Admin para fazer a verificação.

Detectar a revogação do token de ID nas regras de segurança do Firebase

Para poder detectar a revogação do token de ID usando as regras de segurança, primeiro devemos armazenar alguns metadados específicos do usuário.

Atualize metadados específicos do usuário no Firebase Realtime Database.

Salve o carimbo de data/hora de revogação do token de atualização. Isso é necessário para rastrear a revogação do token de ID por meio das regras de segurança do Firebase. Isso permite verificações eficientes no banco de dados. Nos exemplos de código abaixo, use o uid e o tempo de revogação obtidos na seção anterior .

Node.js

const metadataRef = getDatabase().ref('metadata/' + uid);
metadataRef.set({ revokeTime: utcRevocationTimeSecs }).then(() => {
  console.log('Database updated successfully.');
});

Java

DatabaseReference ref = FirebaseDatabase.getInstance().getReference("metadata/" + uid);
Map<String, Object> userData = new HashMap<>();
userData.put("revokeTime", revocationSecond);
ref.setValueAsync(userData);

Pitão

metadata_ref = firebase_admin.db.reference("metadata/" + uid)
metadata_ref.set({'revokeTime': revocation_second})

Adicionar uma verificação às regras de segurança do Firebase

Para impor essa verificação, configure uma regra sem acesso de gravação de cliente para armazenar o tempo de revogação por usuário. Isso pode ser atualizado com o carimbo de data/hora UTC da última hora de revogação, conforme mostrado nos exemplos anteriores:

{
  "rules": {
    "metadata": {
      "$user_id": {
        // this could be false as it is only accessed from backend or rules.
        ".read": "$user_id === auth.uid",
        ".write": "false",
      }
    }
  }
}

Quaisquer dados que requeiram acesso autenticado devem ter a seguinte regra configurada. Essa lógica só permite que usuários autenticados com tokens de ID não revogados acessem os dados protegidos:

{
  "rules": {
    "users": {
      "$user_id": {
        ".read": "auth != null && $user_id === auth.uid && (
            !root.child('metadata').child(auth.uid).child('revokeTime').exists()
          || auth.token.auth_time > root.child('metadata').child(auth.uid).child('revokeTime').val()
        )",
        ".write": "auth != null && $user_id === auth.uid && (
            !root.child('metadata').child(auth.uid).child('revokeTime').exists()
          || auth.token.auth_time > root.child('metadata').child(auth.uid).child('revokeTime').val()
        )",
      }
    }
  }
}

Detecte a revogação do token de ID no SDK.

Em seu servidor, implemente a seguinte lógica para revogação de token de atualização e validação de token de ID:

Quando o token de ID de um usuário deve ser verificado, o sinalizador booleano checkRevoked adicional deve ser passado para verifyIdToken . Se o token do usuário for revogado, o usuário deverá ser desconectado no cliente ou solicitado a reautenticar usando APIs de reautenticação fornecidas pelos SDKs do cliente do Firebase Authentication.

Para inicializar o SDK Admin para sua plataforma, siga as instruções na página de configuração . Exemplos de recuperação do token de ID estão na seção verifyIdToken .

Node.js

// Verify the ID token while checking if the token is revoked by passing
// checkRevoked true.
let checkRevoked = true;
getAuth()
  .verifyIdToken(idToken, checkRevoked)
  .then((payload) => {
    // Token is valid.
  })
  .catch((error) => {
    if (error.code == 'auth/id-token-revoked') {
      // Token has been revoked. Inform the user to reauthenticate or signOut() the user.
    } else {
      // Token is invalid.
    }
  });

Java

try {
  // Verify the ID token while checking if the token is revoked by passing checkRevoked
  // as true.
  boolean checkRevoked = true;
  FirebaseToken decodedToken = FirebaseAuth.getInstance()
      .verifyIdToken(idToken, checkRevoked);
  // Token is valid and not revoked.
  String uid = decodedToken.getUid();
} catch (FirebaseAuthException e) {
  if (e.getAuthErrorCode() == AuthErrorCode.REVOKED_ID_TOKEN) {
    // Token has been revoked. Inform the user to re-authenticate or signOut() the user.
  } else {
    // Token is invalid.
  }
}

Pitão

try:
    # Verify the ID token while checking if the token is revoked by
    # passing check_revoked=True.
    decoded_token = auth.verify_id_token(id_token, check_revoked=True)
    # Token is valid and not revoked.
    uid = decoded_token['uid']
except auth.RevokedIdTokenError:
    # Token revoked, inform the user to reauthenticate or signOut().
    pass
except auth.UserDisabledError:
    # Token belongs to a disabled user record.
    pass
except auth.InvalidIdTokenError:
    # Token is invalid
    pass

Vai

client, err := app.Auth(ctx)
if err != nil {
	log.Fatalf("error getting Auth client: %v\n", err)
}
token, err := client.VerifyIDTokenAndCheckRevoked(ctx, idToken)
if err != nil {
	if err.Error() == "ID token has been revoked" {
		// Token is revoked. Inform the user to reauthenticate or signOut() the user.
	} else {
		// Token is invalid
	}
}
log.Printf("Verified ID token: %v\n", token)

C#

try
{
    // Verify the ID token while checking if the token is revoked by passing checkRevoked
    // as true.
    bool checkRevoked = true;
    var decodedToken = await FirebaseAuth.DefaultInstance.VerifyIdTokenAsync(
        idToken, checkRevoked);
    // Token is valid and not revoked.
    string uid = decodedToken.Uid;
}
catch (FirebaseAuthException ex)
{
    if (ex.AuthErrorCode == AuthErrorCode.RevokedIdToken)
    {
        // Token has been revoked. Inform the user to re-authenticate or signOut() the user.
    }
    else
    {
        // Token is invalid.
    }
}

Responder à revogação de token no cliente

Se o token for revogado por meio do SDK Admin, o cliente será informado da revogação e espera-se que o usuário se reautentique ou seja desconectado:

function onIdTokenRevocation() {
  // For an email/password user. Prompt the user for the password again.
  let password = prompt('Please provide your password for reauthentication');
  let credential = firebase.auth.EmailAuthProvider.credential(
      firebase.auth().currentUser.email, password);
  firebase.auth().currentUser.reauthenticateWithCredential(credential)
    .then(result => {
      // User successfully reauthenticated. New ID tokens should be valid.
    })
    .catch(error => {
      // An error occurred.
    });
}

Segurança avançada: impor restrições de endereço IP

Um mecanismo de segurança comum para detectar roubo de token é acompanhar as origens do endereço IP da solicitação. Por exemplo, se as solicitações são sempre provenientes do mesmo endereço IP (servidor que faz a chamada), as sessões de endereço IP único podem ser impostas. Ou você pode revogar o token de um usuário se detectar que o endereço IP do usuário mudou repentinamente de geolocalização ou se você receber uma solicitação de uma origem suspeita.

Para realizar verificações de segurança com base no endereço IP, para cada solicitação autenticada, inspecione o token de ID e verifique se o endereço IP da solicitação corresponde a endereços IP confiáveis ​​anteriores ou está dentro de um intervalo confiável antes de permitir o acesso a dados restritos. Por exemplo:

app.post('/getRestrictedData', (req, res) => {
  // Get the ID token passed.
  const idToken = req.body.idToken;
  // Verify the ID token, check if revoked and decode its payload.
  admin.auth().verifyIdToken(idToken, true).then((claims) => {
    // Get the user's previous IP addresses, previously saved.
    return getPreviousUserIpAddresses(claims.sub);
  }).then(previousIpAddresses => {
    // Get the request IP address.
    const requestIpAddress = req.connection.remoteAddress;
    // Check if the request IP address origin is suspicious relative to previous
    // IP addresses. The current request timestamp and the auth_time of the ID
    // token can provide additional signals of abuse especially if the IP address
    // suddenly changed. If there was a sudden location change in a
    // short period of time, then it will give stronger signals of possible abuse.
    if (!isValidIpAddress(previousIpAddresses, requestIpAddress)) {
      // Invalid IP address, take action quickly and revoke all user's refresh tokens.
      revokeUserTokens(claims.uid).then(() => {
        res.status(401).send({error: 'Unauthorized access. Please login again!'});
      }, error => {
        res.status(401).send({error: 'Unauthorized access. Please login again!'});
      });
    } else {
      // Access is valid. Try to return data.
      getData(claims).then(data => {
        res.end(JSON.stringify(data);
      }, error => {
        res.status(500).send({ error: 'Server error!' })
      });
    }
  });
});