Single Sign On - SSO

Implementação necessaria para realizar o SSO

  1. O primeiro passo para começar a implementação do fluxo de SSO é a disponibilização de um endpoint com uma chave pública de assinatura. Visite Jwks pra entender mais e sobre como você obtém essa chave.
  2. Criar um Id token do usuario logado, assinado com a chave privada referente à chave pública disponibilizada no endpoint de Jwks. Segue exemplo de payload e implementação programática em C#:
{
  "sub": "{cpf do usuario logado}",
  "jti": "e2e3b202-19e9-46dc-b061-c5f22eb34194",
  "name": "NOME DO USUARIO",
  "email": "[email protected]",
  "phone_number": "{telefone do usuario}", // ex:5511000000000
  "exp": 1706299657,
  "iss": "{base path do endpoint jwks}", //ex: https://id.sandbox.btgpactual.com/.well-known/jwks
  "aud": "btg:empresas:companies:{cnpj}"
}
var claims = new Claim[]
{
    new Claim(JwtRegisteredClaimNames.Sub, ""),
    new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
    new Claim("name", ""),
    new Claim("email", ""),
    new Claim("phone_number", ""),
};

var rsaParameters = rsaKeyForSigning.ExportParameters(true);
var rsaSecurityKey = new RsaSecurityKey(rsaParameters);
var signingCredentials = new SigningCredentials(rsaSecurityKey, SecurityAlgorithms.RsaSha256);

var tokenOptions = new JwtSecurityToken(
    issuer: iss,
    audience: "btg:empresas:companies:{cnpj_onboarding}",
    claims: claims,
    expires: DateTime.Now.AddMinutes(2),
    signingCredentials: signingCredentials
);

var tokenHandler = new JwtSecurityTokenHandler();
var idToken = tokenHandler.WriteToken(tokenOptions);
  1. Após assinar o id token, você deverá obter no endpoint de jwks do BTG Pactual Empresas a chave pública de criptografia
using var httpClient = new HttpClient();
var btgIdJwksEndpoint = "https://id.btgpactual.com/.well-known/jwks";
var jwksResponse = httpClient.GetStringAsync(btgIdJwksEndpoint).Result;
var jwksData = JObject.Parse(jwksResponse);
var encryptionKeyData = jwksData["keys"].FirstOrDefault(k => k["use"].ToString() == "enc");
string e = encryptionKeyData["e"].ToString();
string n = encryptionKeyData["n"].ToString();
Jwk rsaEncryptionKey = new Jwk(e, n);
  1. Com a chave pública de criptografia, você agora deve utilizá-la para gerar um JWE, que nada mais é do que o JWT referente ao id token encriptado.

var headers = new Dictionary<string, object>
{
    { "kid", encryptionKeyData["kid"].ToString() }
};
var recipients = new JweRecipient[]
{
    new JweRecipient(JweAlgorithm.RSA1_5, rsaEncryptionKey, headers)
};
string encryptedJweIdToken = JWE.Encrypt(idToken, recipients, JweEncryption.A256GCM, mode: SerializationMode.Compact);
  1. Com o JWE em mãos você deve criar um RAR(rich authorization request) conforme abaixo:
{
    "type": "btg:empresas:apps:b2b:onboarding",
    "idp": "{parceiro_idp}", //idp do parceiro cadastrado no BtgId
    "principal": "{parceiro_client_id}",
    "resource": "btg:empresas:companies:{cnpj_onboarding}",
    "privileges": "btg:empresas:gatekeeper:apps:onboarding-enrichment"
}
  var authorizationDetails = WebUtility.UrlEncode(JsonConvert.SerializeObject(new[]
  {
      new {
        type = "btg:empresas:apps:b2b:onboarding",
        idp = "{parceiro_idp}", //idp do parceiro cadastrado no BtgId
        principal = "{parceiro_client_id}",
        resource = "btg:empresas:companies:{cnpj_onboarding}",
        privileges = new string[] { "btg:empresas:gatekeeper:apps:onboarding-enrichment" }
      }
  }));
  1. Após realizar o RAR, deve-se realizar um redirecionamento para o seguinte endereço preenchendo os campos com os dados obtidos ao longo do fluxo:
    https://app.empresas.btgpactual.com/conta-pj-btg?idp_hint={parceiro_idp}&acr_values={parceiro_idp}:sso&id_token_hint={encryptedJweIdToken}&authorization_details={authorizationDetails}&redirect=L2NhZGFzdHJvL3BhcmNlaXJv
    Onde:
  • idp_hint: Campo referente ao "idp" presente no RAR.
  • acr_values: Campo referente ao "idp" presente no RAR.
  • id_token_hint: Campo referente ao JWE encriptado.
  • authorization_details: Campo referente à var authorizationDetails
  • redirect: Campo fixo com valor L2NhZGFzdHJvL3BhcmNlaXJv