API de Integração

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:

AmbienteURL
Homologaçãohttps://{UtmSource}.alunos.stage.principia.net/sso?external={external}
Produçãohttps://{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.

Nesta página