Login via SSO
Como implementar o login único (SSO) para o aluno chegar ao portal da Principia sem logar de novo.
Com o login via SSO (Single Sign-On), o aluno acessa o portal da Principia a partir de um link/botão no portal da própria instituição, sem precisar fazer um novo login.
Lib auxiliar
Existe uma lib pronta para esta integração: https://alunos.principia.net/lib/sso-helper.js.
1. Requisição de redirecionamento
Redirecione o aluno para uma destas URLs, conforme o ambiente:
| Ambiente | URL |
|---|---|
| Homologação | https://{UtmSource}.alunos.stage.principia.net/sso?external={external} |
| Produção | https://{UtmSource}.alunos.principia.net/sso?external={external} |
A URL leva dois parâmetros:
UtmSource: código que identifica a sua instituição. É único e fixo (fornecido pela Principia).external: a autorização criptografada, montada nos passos 3-5 abaixo.
2. Parâmetro UtmSource
É só o código que identifica sua instituição perante a Principia, único e fixo, fornecido pelo suporte técnico. Vai literalmente no subdomínio da URL de redirecionamento (https://{UtmSource}.alunos...).
3. Como montar a publicKey
A Principia te envia um token em base64 (via suporte técnico). Decodifique-o e formate como uma chave pública PEM:
/**
* Recebe um token em base64 e retorna a chave no formato RsaPublicKey (PEM).
*/
const getFormattedPublicKey = (key: string) => {
const wordWrap = (str: string) => {
const width = 64;
if (!str) return str;
const regex = "(.{1," + width + "})( +|$\n?)|(.{1," + width + "})";
const result = str.match(RegExp(regex, "g"));
if (!result) return str;
return result.join("\n");
};
let publicKey = "-----BEGIN PUBLIC KEY-----\n";
publicKey += wordWrap(key) + "\n";
return (publicKey += "-----END PUBLIC KEY-----\n");
};
const token = ""; // token em base64 enviado pelo suporte da Principia
/** Decodifica o token para uma string em ASCII */
const key = Buffer.from(token, "base64").toString("ascii");
/** PublicKey gerada a partir do token decodificado */
const publicKey = getFormattedPublicKey(key);4. Função de criptografia
Criptografa com RSA_PKCS1_PADDING, usando a publicKey do passo 3:
import { constants, publicEncrypt } from "crypto";
/**
* Criptografa uma string com RSA_PKCS1_PADDING e retorna base64.
*/
function encrypt(publicKey: string, data: string) {
return publicEncrypt(
{ key: publicKey, padding: constants.RSA_PKCS1_PADDING },
Buffer.from(data, "utf-8"),
).toString("base64");
}5. Como montar e criptografar o parâmetro external
O conteúdo criptografado é um array posicional, nesta ordem exata:
[timestamp(UTC), apikey, CPF];Ordem do array importa
1ª posição: timestamp. 2ª posição: a ApiKey. 3ª posição: o CPF do aluno. A ApiKey aqui é a chave privada de integração da sua instituição, enviada pelo suporte técnico da Principia. Não confunda com o token do passo 3, que é usado só para montar a publicKey.
const apiKey = "SUA_APIKEY_DE_INTEGRACAO"; // apikey privada de integração, fornecida pela Principia
const cpf = "..."; // CPF do aluno que está logando
// Array posicional -> string
const authorizationCryptedAndEncoded = JSON.stringify([
new Date().getTime(),
apiKey,
cpf,
]);
// Criptografa com a publicKey (função "encrypt" do passo 4)
const external = encrypt(publicKey, authorizationCryptedAndEncoded);
// Codifica em base64url para ir na URL
const externalEncoded = Buffer.from(external, "ascii").toString("base64url");
console.log("external (autorização criptografada) -->>", externalEncoded);Use o externalEncoded resultante como o parâmetro external da URL de redirecionamento do passo 1.
6. Comportamento no destino
- Se o aluno já tem login na plataforma, o login é automático.
- Se não tem login, é criado um login usando o CPF enviado na requisição.
- Se os dados do aluno não estiverem integrados previamente na base da Principia, é exibida uma tela de acesso ao suporte (em vez do login automático).
7. Exemplo completo
import { constants, publicEncrypt } from "crypto";
const apiKey = "SUA_APIKEY_DE_INTEGRACAO"; // apikey privada de integração, fornecida pela Principia
const token = ""; // token em base64 enviado pelo suporte da Principia
const cpf = "..."; // CPF do aluno
/**
* Recebe um token em base64 e retorna a chave no formato RsaPublicKey (PEM).
*/
const getFormattedPublicKey = (key: string) => {
const wordWrap = (str: string) => {
const width = 64;
if (!str) return str;
const regex = "(.{1," + width + "})( +|$\n?)|(.{1," + width + "})";
const result = str.match(RegExp(regex, "g"));
if (!result) return str;
return result.join("\n");
};
let publicKey = "-----BEGIN PUBLIC KEY-----\n";
publicKey += wordWrap(key) + "\n";
return (publicKey += "-----END PUBLIC KEY-----\n");
};
/** Decodifica o token para uma string em ASCII */
const key = Buffer.from(token, "base64").toString("ascii");
/** PublicKey gerada a partir do token decodificado */
const publicKey = getFormattedPublicKey(key);
/**
* Criptografa uma string com RSA_PKCS1_PADDING e retorna base64.
*/
function encrypt(publicKey: string, data: string) {
return publicEncrypt(
{ key: publicKey, padding: constants.RSA_PKCS1_PADDING },
Buffer.from(data, "utf-8"),
).toString("base64");
}
// Array posicional [timestamp, apiKey, cpf] -> string
const authorizationCryptedAndEncoded = JSON.stringify([
new Date().getTime(),
apiKey,
cpf,
]);
// Criptografa
const external = encrypt(publicKey, authorizationCryptedAndEncoded);
// Codifica em base64url para a URL
const externalEncoded = Buffer.from(external, "ascii").toString("base64url");
console.log("external (autorização criptografada) -->>", externalEncoded);Chaves e códigos são fornecidos pela Principia
UtmSource, o token (para montar a publicKey) e a apiKey de integração são todos fornecidos pelo suporte técnico da Principia. Peça-os com o seu ponto de contato ou pelo grupo do WhatsApp de integração antes de implementar.
O SSO é independente do restante da integração de dados (envio de alunos, parcelas, etc.), pode ser implementado antes, depois ou em paralelo, conforme a prioridade da sua instituição.