← Início
Plataforma Semente — Integração SSO
Versão 1.0

Integração SSO — Especificação Técnica

Plataforma Semente

Versão 1.0 — Documento destinado a parceiros integradores

1. Visão Geral

1.1 Objetivo

Este documento especifica como um sistema parceiro deve se integrar ao mecanismo de Single Sign-On (SSO) da Plataforma Semente. O objetivo é permitir que um usuário já autenticado no sistema do parceiro (por exemplo, o sistema de gestão escolar) acesse a Plataforma Semente sem precisar realizar um novo login manual.

A integração é feita através da geração de um token assinado (JWT) pelo parceiro, enviado a um endpoint HTTP da Semente, que valida o token e autentica o usuário correspondente.

1.2 Fluxo Resumido

  1. O usuário se autentica normalmente no sistema do parceiro.
  2. O sistema do parceiro gera um token JWT assinado, identificando o usuário.
  3. O parceiro envia esse token para o endpoint de SSO da Semente.
  4. A Semente valida o token e autentica o usuário na Plataforma Semente.
  5. A Semente retorna uma sessão de acesso válida.
Importante: Toda a lógica de geração e assinatura do token deve ocorrer no back-end do parceiro. O secret de assinatura nunca deve ser exposto no front-end, em aplicativos móveis ou em qualquer código acessível ao usuário final.

1.3 Diagrama do Fluxo

O diagrama abaixo ilustra a sequência completa da integração, desde o login do usuário no sistema do parceiro até o acesso à Plataforma Semente:

Usuário Sistema do Parceiro Plataforma Semente 1. Login no sistema do parceiro 2. Gera JWT (assinado com o secret HS256) 3. POST /sso_custom { "token": "<JWT>" } 4. Validações • Assinatura (secret) • Audience / Issuer • Expiração (exp) • Reuso do jti (replay) 5. Autentica o login (método já existente) 6. 200 OK — sessão de acesso 7. Redireciona usuário autenticado 8. Usuário navega na Plataforma Semente Se alguma validação do passo 4 falhar: a Semente responde com 401 (ou 400) diretamente ao parceiro no passo 6, sem autenticar nenhum usuário — o fluxo é interrompido ali.

Caso qualquer validação do passo 4 falhe (assinatura, audience/issuer, expiração ou reuso do jti), a Semente responde com erro diretamente ao parceiro, e nenhum usuário é autenticado.

2. Pré-requisitos

2.1 Dados fornecidos pela Semente

Antes de iniciar a implementação, a Semente fornecerá ao parceiro, por canal seguro, os seguintes dados:

  • Client ID: identificador único do parceiro.
  • Secret: chave de 256 bits, codificada em Base64, usada para assinar o token (HMAC-SHA256).
Atenção: O secret deve ser armazenado de forma segura (cofre de segredos, variável de ambiente protegida, etc.) e nunca deve ser versionado em repositórios de código.

2.2 Sobre a Codificação em Base64

O secret é gerado pela Semente como uma sequência de bytes aleatórios e entregue ao parceiro já codificado em Base64 — essa codificação existe apenas para que um valor binário possa ser transmitido e copiado como texto (e-mail, painel, etc.).

O parceiro não precisa gerar nem codificar nada em Base64. O único passo necessário do lado do parceiro é decodificar a string recebida de volta para bytes brutos antes de usá-la como chave de assinatura HMAC — exatamente como mostrado nos exemplos da seção 5 (Convert.FromBase64String, base64.b64decode, Base64.getDecoder().decode, entre outros).

3. Especificação do Token (JWT)

O token utilizado é um JSON Web Token (JWT), assinado com o algoritmo HMAC-SHA256 (HS256). É um padrão aberto, com bibliotecas disponíveis para praticamente qualquer linguagem de programação.

3.1 Claims Obrigatórias

ClaimObrigatórioDescrição
subSimLogin do usuário na Plataforma Semente (o mesmo identificador já usado hoje no login direto).
issSimClient ID do parceiro, fornecido pela Semente no momento do provisionamento.
audSimValor fixo "plataforma-semente". Deve ser copiado literalmente (case-sensitive).
jtiSimIdentificador único do token (UUID v4). Usado para impedir reuso do mesmo token.
iatSimData/hora de emissão do token (UTC).
nbfSimData/hora a partir da qual o token é válido (UTC). Deve ser igual a iat.
expSimData/hora de expiração do token (UTC). Deve ser iat + 5 minutos.

3.2 Algoritmo e Chave

  • Algoritmo de assinatura: HS256 (HMAC-SHA256). Nenhum outro algoritmo é aceito.
  • Chave de assinatura: o secret fornecido pela Semente, decodificado de Base64 para bytes brutos antes de assinar.

3.3 Regras de Validade

  • O token deve ter validade de exatamente 5 minutos entre iat e exp.
  • Cada token deve conter um jti único (recomenda-se UUID v4). Um token com o mesmo jti não pode ser reenviado — a segunda tentativa será rejeitada, mesmo dentro da janela de validade.
  • O relógio do sistema do parceiro deve estar sincronizado (NTP). Diferenças de horário podem causar rejeição indevida do token.

4. Endpoint de Integração

4.1 URL e Método

O parceiro deve enviar o token via requisição HTTP POST para:

Endpoint
POST https://integracao.sementeeducacao.com.br/api/v0/accounts/sso_custom

4.2 Formato da Requisição

O corpo da requisição deve ser um JSON contendo o token no campo token:

Requisição
POST /api/v0/accounts/sso_custom HTTP/1.1
Host: integracao.sementeeducacao.com.br
Content-Type: application/json

{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJqb2FvLnNpbHZhIiwi..."
}

4.3 Respostas

Em caso de sucesso, a Semente retorna a sessão de acesso:

200 OK
HTTP/1.1 200 OK
Content-Type: application/json

{
  "sessionToken": "...",
  "expiresIn": 3600
}

Em caso de falha de validação:

401 Unauthorized
HTTP/1.1 401 Unauthorized
Content-Type: application/json

{
  "error": "invalid_token",
  "message": "Token expirado ou já utilizado"
}

Códigos de retorno possíveis:

HTTPSituaçãoDescrição
200SucessoToken válido. A resposta contém a sessão de acesso à Plataforma Semente.
401Não autorizadoAssinatura inválida, client_id desconhecido, token expirado, ou token já utilizado (replay).
400Requisição inválidaCorpo da requisição malformado ou claims obrigatórias ausentes.

5. Exemplos de Geração do JWT

A seguir, exemplos de geração do token nas linguagens mais comuns. Todos produzem um token equivalente, seguindo a especificação da seção 3.

5.1 C# (.NET)

Bibliotecas: System.IdentityModel.Tokens.Jwt e Microsoft.IdentityModel.Tokens (NuGet).

C#
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using Microsoft.IdentityModel.Tokens;

// client_id e secret são fornecidos pela Semente no provisionamento
string clientId = "SEU_CLIENT_ID";
string secretBase64 = "SEU_SECRET_BASE64";
string login = "joao.silva";

var key = new SymmetricSecurityKey(Convert.FromBase64String(secretBase64));
var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var now = DateTime.UtcNow;

var claims = new[]
{
    new Claim(JwtRegisteredClaimNames.Sub, login),
    new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
};

var token = new JwtSecurityToken(
    issuer: clientId,
    audience: "plataforma-semente",
    claims: claims,
    notBefore: now,
    expires: now.AddMinutes(5),
    signingCredentials: credentials
);

string jwt = new JwtSecurityTokenHandler().WriteToken(token);

5.2 Python

Biblioteca: PyJWT (pip install pyjwt).

Python
import jwt
import uuid
import base64
from datetime import datetime, timedelta, timezone

# client_id e secret são fornecidos pela Semente no provisionamento
client_id = "SEU_CLIENT_ID"
secret = base64.b64decode("SEU_SECRET_BASE64")
login = "joao.silva"

now = datetime.now(timezone.utc)

payload = {
    "sub": login,
    "iss": client_id,
    "aud": "plataforma-semente",
    "jti": str(uuid.uuid4()),
    "iat": now,
    "nbf": now,
    "exp": now + timedelta(minutes=5),
}

jwt_token = jwt.encode(payload, secret, algorithm="HS256")

5.3 Java

Biblioteca: io.jsonwebtoken:jjwt (jjwt-api, jjwt-impl, jjwt-jackson).

Java
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;

import javax.crypto.SecretKey;
import java.util.Base64;
import java.util.Date;
import java.util.UUID;

// client_id e secret são fornecidos pela Semente no provisionamento
String clientId = "SEU_CLIENT_ID";
byte[] secretBytes = Base64.getDecoder().decode("SEU_SECRET_BASE64");
SecretKey key = Keys.hmacShaKeyFor(secretBytes);
String login = "joao.silva";

Date now = new Date();
Date exp = new Date(now.getTime() + 5 * 60 * 1000);

String jwt = Jwts.builder()
        .setSubject(login)
        .setIssuer(clientId)
        .setAudience("plataforma-semente")
        .setId(UUID.randomUUID().toString())
        .setIssuedAt(now)
        .setNotBefore(now)
        .setExpiration(exp)
        .signWith(key, SignatureAlgorithm.HS256)
        .compact();

5.4 Node.js

Biblioteca: jsonwebtoken (npm install jsonwebtoken).

Node.js
const jwt = require("jsonwebtoken");
const { randomUUID } = require("crypto");

// client_id e secret são fornecidos pela Semente no provisionamento
const clientId = "SEU_CLIENT_ID";
const secret = Buffer.from("SEU_SECRET_BASE64", "base64");
const login = "joao.silva";

const now = Math.floor(Date.now() / 1000);

const token = jwt.sign(
  {
    sub: login,
    iss: clientId,
    aud: "plataforma-semente",
    jti: randomUUID(),
    iat: now,
    nbf: now,
    exp: now + 5 * 60,
  },
  secret,
  { algorithm: "HS256" }
);

5.5 PHP

Biblioteca: firebase/php-jwt (composer require firebase/php-jwt).

PHP
<?php
require 'vendor/autoload.php';
use Firebase\JWT\JWT;

// client_id e secret são fornecidos pela Semente no provisionamento
$clientId = "SEU_CLIENT_ID";
$secret = base64_decode("SEU_SECRET_BASE64");
$login = "joao.silva";

$now = time();

$payload = [
    "sub" => $login,
    "iss" => $clientId,
    "aud" => "plataforma-semente",
    "jti" => bin2hex(random_bytes(16)),
    "iat" => $now,
    "nbf" => $now,
    "exp" => $now + (5 * 60),
];

$jwt = JWT::encode($payload, $secret, "HS256");

6. Checklist de Implementação

7. Perguntas Frequentes

A segunda tentativa será rejeitada com erro 401, mesmo que o token ainda esteja dentro da janela de validade de 5 minutos. Cada token só pode ser usado uma vez.
Não. A janela de 5 minutos é fixa e faz parte da especificação de segurança da integração.
Tokens podem ser rejeitados por parecerem expirados ou ainda não válidos, mesmo tendo sido gerados corretamente. Recomendamos manter o servidor sincronizado via NTP.
Não é recomendado. Cada integração deve ter seu próprio par de credenciais, fornecido pela Semente conforme a necessidade.
Entre em contato com o time técnico da Semente através do canal combinado no momento do provisionamento das credenciais.