These docs are for v2.1. Click to read the latest docs for v4.1.

Connect Challenge

Possibilita a criação de um token e um desafio a ser utilizados como segundo fator de autenticação apenas para a API de Transferência.

Essa documentação se refere ao processo de gerar um token e um challenge a ser utilizado como segundo fator de segurança na integração com algumas APIs do PagSeguro. Isso se dá através da utilização de um par de chaves, pública e privada, que fornecem segurança através de criptografia. Nem mesmo senhas extremamente longas poderiam oferecer o mesmo nível de segurança

Para a geração do token é necessário seguir o descrito abaixo:

1º: Criar uma conta no nosso ambiente de Sandbox

Para criar uma conta no ambiente de Sandbox utilize este link: Criação de conta em Sandbox

2º passo: Gerar par de chaves pública e privada.

Tratando-se da chave 'pública', esta deve ser gerada no formato x.509 (SPKI) e tratando-se da chave 'privada', esta deve ser gerada no formato PKCS8.
Abaixo, exemplos de como gerar o par de chaves em diferentes linguagens

#> openssl genpkey -algorithm RSA -out private-key -pkeyopt rsa_keygen_bits:2048
#> openssl rsa -pubout -in private-key -out public-key
public static void main(String[] args) throws Exception {
    KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
    keyPairGenerator.initialize(2048);
    KeyPair keyPair = keyPairGenerator.generateKeyPair();

    System.out.println(Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded()));
    System.out.println(Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded()));
}
fun main(args: Array<String>) {
    val keyPair = KeyPairGenerator.getInstance("RSA")
        .apply { this.initialize(2048) }.generateKeyPair()
    println(Base64.getEncoder().encodeToString(keyPair.public.encoded))
    println(Base64.getEncoder().encodeToString(keyPair.private.encoded))
}
using System.Security.Cryptography;

var rsa = RSA.Create(2048);
var pubKey = rsa.ExportSubjectPublicKeyInfo();
var privKey = rsa.ExportRSAPrivateKey();

Console.WriteLine(Convert.ToBase64String(pubKey));
Console.WriteLine("-------------");
Console.WriteLine(Convert.ToBase64String(privKey));
var crypto = require('crypto');

crypto.generateKeyPair('rsa',
{
    modulusLength: 2048,
    publicKeyEncoding: {
      type: 'spki',
      format: 'pem'
    },
    privateKeyEncoding: {
      type: 'pkcs8',
      format: 'pem',
    }
  }
, (error, pubKey, pvtKey) => {
    console.log(pubKey);
    console.log(pvtKey);
});

📘

Importante:

As chaves pública e privada geradas precisam ter, no mínimo, 2048bits.

Após gerar as chaves, você deve disponibilizar apenas a chave pública em um endpoint (GET), e o 'Content-Type: application/json', para podermos consultá-la no seguinte formato:

{
  "public_key": "public_key",
  "created_at": 1580237849044
}

Onde:

  • public_key - sua chave pública gerada no formato pem
  • created_at - a data em que ela foi gerada no formato timestamp. Um parâmetro do tipo long

🚧

Atenção

A chave privada é confidenciais. Recomendamos não compartilhá-la em ambientes públicos ou com terceiros e recomendamos salvá-la em um local seguro.

3º passo: Informar a URL do endpoint gerado no passo 2:

Para informar a URL do ambiente de Sandbox, abra uma solicitação no Portal PagSeguro, através [deste link] (https://app.pipefy.com/public/form/PsAVEzo8), informando o nome da sua empresa, o e-mail registrado na Pagseguro e a URL pertinente ao ambiente no qual você está se integrando. O SLA de resposta é de até 2 dias úteis.

Para informar a URL do ambiente de Produção, acesse no seu ibanking (conta web): vendas online -> integração -> cadastro da URL. Com isso, sua URL já estará cadastrada em produção.

4º passo: Solicitar geração do Challenge e access token com autorização no escopo "certificate.create" para geração do seu certificado digital

🚧

Esse passo só deverá ser realizado após a devolutiva do chamado aberto no passo anterior. A URL gerada precisa estar cadastrada para podermos prosseguir com o processo.

Você deve solicitar a geração do seu access token e challenge em Obter o access token informando o escopo disposto abaixo e grand_type challenge .

Escopos disponíveis:

NomeDescrição
certificate.createPossibilita solicitar a criação de um certificado digital
curl --request POST \
     --url https://sandbox.api.pagseguro.com/oauth2/token \
     --header 'Accept: application/json' \
     --header 'Content-Type: application/json' \
     --header 'Authorization: Bearer ${TOKEN}' \
     --data '
{
     "grant_type": "challenge",
     "scope": "certificate.create"
}'

Como resposta você receberá um Challenge criptografado com sua chave pública que obtemos no endpoint informado no 3 passo, e codificado em base64, é necessário decodificá-lo e, após isso, descriptografá-lo utilizando a sua chave privada.

O Challenge funciona de forma muito simples, através de sua chave pública é realizada uma criptografia usando algoritmo RSA, a string resulta no processo de criptografia poderá ser descriptografada apenas usando a chave privada (par da chave pública) que você tem posse e a mantém de forma segura.

Após descriptografá-lo você conseguirá utilizar essa informação, juntamente com o token gerado, em sua próxima requisição que necessitá-la.

📘

Importante! Tempo de validade do token:

O token gerado será utilizado na próxima requisição e seu tempo de validade é de 30 segundos

5º passo: Descriptografando o desafio

Para descriptogravar o desafio, deve-se usar como estratégia de Padding o mecanismo OAEP, MGF1 como função geradora de máscara e SHA-256 como algoritmo de hash.
Abaixo, alguns exemplos de como descriptografar seu desafio utilizando a configuração descrita acima:

import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.spec.MGF1ParameterSpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;

import javax.crypto.Cipher;
import javax.crypto.spec.OAEPParameterSpec;
import javax.crypto.spec.PSource;

public class Main {

    public static void main(String[] args) throws Exception {
        String privateKey = Files.readString(Paths.get("<private_key_dir_path>"));
        privateKey = privateKey.replace("-----BEGIN PRIVATE KEY-----", "")
			     .replaceAll(System.lineSeparator(), "")
			     .replace("-----END PRIVATE KEY-----", "");

		byte[] decodedPrivateKey = Base64.getDecoder().decode(privateKey);
		
        var privateKeySpec = new PKCS8EncodedKeySpec(decodedPrivateKey);
        var privateKkeyFactory = KeyFactory.getInstance("RSA");
        PrivateKey pvtKey = privateKkeyFactory.generatePrivate(privateKeySpec);

        
        OAEPParameterSpec oaepParams = new OAEPParameterSpec("SHA-256", "MGF1", new MGF1ParameterSpec("SHA-256"), PSource.PSpecified.DEFAULT);
		
		Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
        cipher.init(Cipher.DECRYPT_MODE, pvtKey, oaepParams);

        byte[] decodedChallenge = Base64.getDecoder().decode("<crypted_challenge>");
        byte[] decipheredChallenge = cipher.doFinal(decodedChallenge);

        System.out.println(new String(decipheredChallenge));
    }
}
var crypto = require('crypto');
var fs = require('fs');

const privateKeyPem = fs.readFileSync('<private_key_dir_path>');
const privateKey = crypto.createPrivateKey({key: privateKeyPem});
const decryptedData = crypto.privateDecrypt(
    {
        key: privateKey,
        padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
        oaepHash: 'sha256'
    }, Buffer.from('<encrypted_challenge>', 'base64'));

console.log(decryptedData.toString());
using System.Security.Cryptography;

var privateKey = "<load_private_key>";
var challenge = "<input_server_generated_challenge>";

var rsa = RSA.Create();
rsa.ImportPkcs8PrivateKey(Convert.FromBase64String(privateKey), out _);

var decrypted = rsa.Decrypt(Convert.FromBase64String(challenge), RSAEncryptionPadding.OaepSHA256);

Console.WriteLine(System.Text.Encoding.Default.GetString(decrypted));