🔐 Fluxo de Login
Este guia apresenta o fluxo completo de autenticação para usuários já cadastrados no sistema.
📋 Visão Geral
O fluxo de login permite que usuários autentiquem-se usando CPF e senha, gerando tokens de acesso OAuth 2.0 válidos por 5 minutos.
URLs Base:
- Homologação:
https://ssohml.credsystem.com.br/auth/realms/{realm}/protocol/openid-connect - Produção:
https://ssoprd.credsystem.com.br/auth/realms/{realm}/protocol/openid-connect
- 🔧 Guia de Troubleshooting - Solução de problemas e erros comuns
- 📖 Especificação OpenAPI — Referência técnica completa (schemas, tipos, exemplos)
🔑 1. Login com Usuário e Senha
Para autenticar um usuário no sistema, você precisa gerar um token de acesso OAuth 2.0.
Endpoint
POST https://ssohml.credsystem.com.br/auth/realms/{realm}/protocol/openid-connect/token
Content-Type: application/x-www-form-urlencoded
Exemplos de Código
- cURL
- JavaScript
- Python
- Java
- C#
- PHP
- Go
curl -X POST 'https://ssohml.credsystem.com.br/auth/realms/{realm}/protocol/openid-connect/token' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'client_id=YOUR_CLIENT_ID' \
-d 'client_secret=YOUR_CLIENT_SECRET' \
-d 'username=12345678909' \
-d 'password=SenhaDoUsuario' \
-d 'grant_type=password' \
-d 'infosAdicionais={"dispositivoId":"device123","modelo":"Samsung Galaxy"}'
const response = await fetch('https://ssohml.credsystem.com.br/auth/realms/{realm}/protocol/openid-connect/token', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
client_id: 'YOUR_CLIENT_ID',
client_secret: 'YOUR_CLIENT_SECRET',
username: '12345678909',
password: 'SenhaDoUsuario',
grant_type: 'password',
infosAdicionais: JSON.stringify({ dispositivoId: 'device123', modelo: 'Samsung Galaxy' })
})
});
const data = await response.json();
console.log(data.access_token);
import requests, json
url = 'https://ssohml.credsystem.com.br/auth/realms/{realm}/protocol/openid-connect/token'
data = {
'client_id': 'YOUR_CLIENT_ID',
'client_secret': 'YOUR_CLIENT_SECRET',
'username': '12345678909',
'password': 'SenhaDoUsuario',
'grant_type': 'password',
'infosAdicionais': json.dumps({'dispositivoId': 'device123', 'modelo': 'Samsung Galaxy'})
}
response = requests.post(url, data=data)
tokens = response.json()
print(tokens['access_token'])
import java.net.http.*;
import java.net.URI;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Map;
Map<String, String> params = Map.of(
"client_id", "YOUR_CLIENT_ID",
"client_secret", "YOUR_CLIENT_SECRET",
"username", "12345678909",
"password", "SenhaDoUsuario",
"grant_type", "password",
"infosAdicionais", "{\"dispositivoId\":\"device123\"}"
);
String form = params.entrySet().stream()
.map(e -> URLEncoder.encode(e.getKey(), StandardCharsets.UTF_8)
+ "=" + URLEncoder.encode(e.getValue(), StandardCharsets.UTF_8))
.reduce("", (a, b) -> a.isEmpty() ? b : a + "&" + b);
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://ssohml.credsystem.com.br/auth/realms/{realm}/protocol/openid-connect/token"))
.header("Content-Type", "application/x-www-form-urlencoded")
.POST(HttpRequest.BodyPublishers.ofString(form))
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
using System.Net.Http;
var client = new HttpClient();
var content = new FormUrlEncodedContent(new Dictionary<string, string> {
["client_id"] = "YOUR_CLIENT_ID",
["client_secret"] = "YOUR_CLIENT_SECRET",
["username"] = "12345678909",
["password"] = "SenhaDoUsuario",
["grant_type"] = "password",
["infosAdicionais"] = "{\"dispositivoId\":\"device123\"}"
});
var response = await client.PostAsync(
"https://ssohml.credsystem.com.br/auth/realms/{realm}/protocol/openid-connect/token",
content
);
response.EnsureSuccessStatusCode();
var json = await response.Content.ReadAsStringAsync();
$data = http_build_query([
'client_id' => 'YOUR_CLIENT_ID',
'client_secret' => 'YOUR_CLIENT_SECRET',
'username' => '12345678909',
'password' => 'SenhaDoUsuario',
'grant_type' => 'password',
'infosAdicionais' => json_encode(['dispositivoId' => 'device123', 'modelo' => 'Samsung Galaxy'])
]);
$ch = curl_init('https://ssohml.credsystem.com.br/auth/realms/{realm}/protocol/openid-connect/token');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/x-www-form-urlencoded']);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);
echo $response['access_token'];
import (
"encoding/json"
"net/http"
"net/url"
)
infos, _ := json.Marshal(map[string]string{"dispositivoId": "device123", "modelo": "Samsung Galaxy"})
data := url.Values{
"client_id": {"YOUR_CLIENT_ID"},
"client_secret": {"YOUR_CLIENT_SECRET"},
"username": {"12345678909"},
"password": {"SenhaDoUsuario"},
"grant_type": {"password"},
"infosAdicionais": {string(infos)},
}
resp, _ := http.PostForm(
"https://ssohml.credsystem.com.br/auth/realms/{realm}/protocol/openid-connect/token",
data,
)
defer resp.Body.Close()
var tokens map[string]interface{}
json.NewDecoder(resp.Body).Decode(&tokens)
fmt.Println(tokens["access_token"])
📥 Parâmetros da Requisição
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
client_id | string | ✅ | ID do cliente fornecido pela equipe |
client_secret | string | ✅ | Secret do cliente (mantenha seguro!) |
username | string | ✅ | CPF do usuário (apenas números) |
password | string | ✅ | Senha do usuário |
grant_type | string | ✅ | Fixo: password |
infosAdicionais | JSON string | ✅ | Informações do dispositivo codificadas |
📤 Resposta de Sucesso
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI...",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI...",
"expires_in": 300,
"refresh_expires_in": 1800,
"token_type": "Bearer",
"not-before-policy": 0,
"session_state": "f3d2e1c0-b9a8-7654-3210-abcdef123456",
"scope": "profile email"
}
- Guarde o
access_tokene orefresh_tokende forma segura - O
access_tokenexpira em 5 minutos (expires_in: 300) - Use o
refresh_tokenpara renovar sem pedir credenciais novamente - NUNCA exponha o
client_secretem código frontend
O grant type password é adequado apenas para aplicações mobile/desktop de primeira parte. Para aplicações web, use Authorization Code Flow com PKCE.
Consulte o 🔧 Troubleshooting - Obter Token para detalhes de erros e soluções.
🔄 2. Renovação de Token (Refresh Token)
Quando o token de acesso expirar (após 5 minutos), você pode renová-lo usando o refresh token sem precisar das credenciais do usuário.
Endpoint
POST https://ssohml.credsystem.com.br/auth/realms/{realm}/protocol/openid-connect/token
Content-Type: application/x-www-form-urlencoded
Exemplos de Código
- cURL
- JavaScript
- Python
- Java
- C#
- PHP
- Go
curl -X POST 'https://ssohml.credsystem.com.br/auth/realms/{realm}/protocol/openid-connect/token' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'client_id=YOUR_CLIENT_ID' \
-d 'client_secret=YOUR_CLIENT_SECRET' \
-d 'refresh_token=eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldU...' \
-d 'grant_type=refresh_token'
async function refreshAccessToken(refreshToken) {
const response = await fetch(
'https://ssohml.credsystem.com.br/auth/realms/{realm}/protocol/openid-connect/token',
{
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
client_id: 'YOUR_CLIENT_ID',
client_secret: 'YOUR_CLIENT_SECRET',
refresh_token: refreshToken,
grant_type: 'refresh_token'
})
}
);
if (!response.ok) throw new Error('Token refresh failed');
return await response.json();
}
import requests
def refresh_access_token(refresh_token):
url = 'https://ssohml.credsystem.com.br/auth/realms/{realm}/protocol/openid-connect/token'
data = {
'client_id': 'YOUR_CLIENT_ID',
'client_secret': 'YOUR_CLIENT_SECRET',
'refresh_token': refresh_token,
'grant_type': 'refresh_token'
}
response = requests.post(url, data=data)
response.raise_for_status()
return response.json()
import java.net.http.*;
import java.net.URI;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Map;
Map<String, String> params = Map.of(
"client_id", "YOUR_CLIENT_ID",
"client_secret", "YOUR_CLIENT_SECRET",
"refresh_token", refreshToken,
"grant_type", "refresh_token"
);
String form = params.entrySet().stream()
.map(e -> URLEncoder.encode(e.getKey(), StandardCharsets.UTF_8)
+ "=" + URLEncoder.encode(e.getValue(), StandardCharsets.UTF_8))
.reduce("", (a, b) -> a.isEmpty() ? b : a + "&" + b);
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://ssohml.credsystem.com.br/auth/realms/{realm}/protocol/openid-connect/token"))
.header("Content-Type", "application/x-www-form-urlencoded")
.POST(HttpRequest.BodyPublishers.ofString(form))
.build();
HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());
using System.Net.Http;
var client = new HttpClient();
var content = new FormUrlEncodedContent(new Dictionary<string, string> {
["client_id"] = "YOUR_CLIENT_ID",
["client_secret"] = "YOUR_CLIENT_SECRET",
["refresh_token"] = refreshToken,
["grant_type"] = "refresh_token"
});
var response = await client.PostAsync(
"https://ssohml.credsystem.com.br/auth/realms/{realm}/protocol/openid-connect/token",
content
);
response.EnsureSuccessStatusCode();
var json = await response.Content.ReadAsStringAsync();
$data = http_build_query([
'client_id' => 'YOUR_CLIENT_ID',
'client_secret' => 'YOUR_CLIENT_SECRET',
'refresh_token' => $refreshToken,
'grant_type' => 'refresh_token'
]);
$ch = curl_init('https://ssohml.credsystem.com.br/auth/realms/{realm}/protocol/openid-connect/token');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/x-www-form-urlencoded']);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);
import (
"encoding/json"
"net/http"
"net/url"
)
data := url.Values{
"client_id": {"YOUR_CLIENT_ID"},
"client_secret": {"YOUR_CLIENT_SECRET"},
"refresh_token": {refreshToken},
"grant_type": {"refresh_token"},
}
resp, _ := http.PostForm(
"https://ssohml.credsystem.com.br/auth/realms/{realm}/protocol/openid-connect/token",
data,
)
defer resp.Body.Close()
var tokens map[string]interface{}
json.NewDecoder(resp.Body).Decode(&tokens)
📥 Parâmetros da Requisição
| Parâmetro | Tipo | Descrição |
|---|---|---|
client_id | string | ID do cliente |
client_secret | string | Secret do cliente |
refresh_token | string | Refresh token obtido no login |
grant_type | string | Fixo: refresh_token |
Renove o token antes de expirar:
- Configure um timer para renovar 1 minuto antes da expiração
- Ou renove automaticamente ao receber erro 401 em suas requisições
Consulte o 🔧 Troubleshooting - Obter Token para detalhes de erros e soluções.
🤖 3. Autenticação com Service Account
Para operações que não envolvem um usuário específico (server-to-server), use a autenticação de service account.
Endpoint
POST https://ssohml.credsystem.com.br/auth/realms/{realm}/protocol/openid-connect/token
Content-Type: application/x-www-form-urlencoded
Exemplos de Código
- cURL
- JavaScript
- Python
- Java
- C#
- PHP
- Go
curl -X POST 'https://ssohml.credsystem.com.br/auth/realms/{realm}/protocol/openid-connect/token' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'client_id=YOUR_SERVICE_ACCOUNT_ID' \
-d 'client_secret=YOUR_SERVICE_ACCOUNT_SECRET' \
-d 'grant_type=client_credentials'
const response = await fetch(
'https://ssohml.credsystem.com.br/auth/realms/{realm}/protocol/openid-connect/token',
{
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
client_id: 'YOUR_SERVICE_ACCOUNT_ID',
client_secret: 'YOUR_SERVICE_ACCOUNT_SECRET',
grant_type: 'client_credentials'
})
}
);
const { access_token } = await response.json();
import requests
def autenticar_service_account():
url = 'https://ssohml.credsystem.com.br/auth/realms/{realm}/protocol/openid-connect/token'
data = {
'client_id': 'YOUR_SERVICE_ACCOUNT_ID',
'client_secret': 'YOUR_SERVICE_ACCOUNT_SECRET',
'grant_type': 'client_credentials'
}
response = requests.post(url, data=data)
response.raise_for_status()
return response.json()['access_token']
import java.net.http.*;
import java.net.URI;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Map;
Map<String, String> params = Map.of(
"client_id", "YOUR_SERVICE_ACCOUNT_ID",
"client_secret", "YOUR_SERVICE_ACCOUNT_SECRET",
"grant_type", "client_credentials"
);
String form = params.entrySet().stream()
.map(e -> URLEncoder.encode(e.getKey(), StandardCharsets.UTF_8)
+ "=" + URLEncoder.encode(e.getValue(), StandardCharsets.UTF_8))
.reduce("", (a, b) -> a.isEmpty() ? b : a + "&" + b);
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://ssohml.credsystem.com.br/auth/realms/{realm}/protocol/openid-connect/token"))
.header("Content-Type", "application/x-www-form-urlencoded")
.POST(HttpRequest.BodyPublishers.ofString(form))
.build();
HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());
using System.Net.Http;
var client = new HttpClient();
var content = new FormUrlEncodedContent(new Dictionary<string, string> {
["client_id"] = "YOUR_SERVICE_ACCOUNT_ID",
["client_secret"] = "YOUR_SERVICE_ACCOUNT_SECRET",
["grant_type"] = "client_credentials"
});
var response = await client.PostAsync(
"https://ssohml.credsystem.com.br/auth/realms/{realm}/protocol/openid-connect/token",
content
);
response.EnsureSuccessStatusCode();
var json = await response.Content.ReadAsStringAsync();
$data = http_build_query([
'client_id' => 'YOUR_SERVICE_ACCOUNT_ID',
'client_secret' => 'YOUR_SERVICE_ACCOUNT_SECRET',
'grant_type' => 'client_credentials'
]);
$ch = curl_init('https://ssohml.credsystem.com.br/auth/realms/{realm}/protocol/openid-connect/token');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/x-www-form-urlencoded']);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);
echo $response['access_token'];
import (
"encoding/json"
"net/http"
"net/url"
)
data := url.Values{
"client_id": {"YOUR_SERVICE_ACCOUNT_ID"},
"client_secret": {"YOUR_SERVICE_ACCOUNT_SECRET"},
"grant_type": {"client_credentials"},
}
resp, _ := http.PostForm(
"https://ssohml.credsystem.com.br/auth/realms/{realm}/protocol/openid-connect/token",
data,
)
defer resp.Body.Close()
var tokens map[string]interface{}
json.NewDecoder(resp.Body).Decode(&tokens)
fmt.Println(tokens["access_token"])
Use service account para:
- Tarefas agendadas
- Processos em background
- Integrações backend-to-backend
- Operações em lote
Consulte o 🔧 Troubleshooting - Obter Token para detalhes de erros e soluções.
👤 4. Gerenciamento de Sessão
Buscar Informações da Sessão
Após o login, você pode consultar informações sobre a sessão atual do usuário.
Authorization: Bearer {token}
Exemplo de Resposta
{
"usuario": {
"cpf": "12345678909",
"nome": "João Silva",
"email": "joao.silva@example.com"
},
"sessao": {
"id": "f3d2e1c0-b9a8-7654-3210",
"dataInicio": "2025-12-03T10:30:00Z",
"dispositivo": {
"id": "device123",
"modelo": "Samsung Galaxy S21"
}
}
}
Para uso interno, existe também: GET {baseUrlInterna}/sessao/info
Buscar Informações por CPF (Service Account)
Com um token de service account, você pode buscar informações de usuário por CPF.
Authorization: Bearer {token}
APP: nome-do-app
- cURL
- JavaScript
- Python
- Java
- C#
- PHP
- Go
curl -X GET '{baseUrl}/usuario/sso/info/12345678909' \
-H 'Authorization: Bearer {service-account-token}' \
-H 'APP: meu-app-private-label'
const response = await fetch(
`${baseUrl}/usuario/sso/info/12345678909`,
{
headers: {
'Authorization': `Bearer ${serviceAccountToken}`,
'APP': 'meu-app-private-label'
}
}
);
const userInfo = await response.json();
import requests
def buscar_info_cpf(cpf, token, app_name):
url = f"{base_url}/usuario/sso/info/{cpf}"
headers = {
'Authorization': f'Bearer {token}',
'APP': app_name
}
response = requests.get(url, headers=headers)
response.raise_for_status()
return response.json()
import java.net.http.*;
import java.net.URI;
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(baseUrl + "/usuario/sso/info/12345678909"))
.header("Authorization", "Bearer " + serviceAccountToken)
.header("APP", "meu-app-private-label")
.GET()
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
using System.Net.Http;
var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", $"Bearer {serviceAccountToken}");
client.DefaultRequestHeaders.Add("APP", "meu-app-private-label");
var response = await client.GetAsync($"{baseUrl}/usuario/sso/info/12345678909");
response.EnsureSuccessStatusCode();
var userInfo = await response.Content.ReadAsStringAsync();
$cpf = '12345678909';
$ch = curl_init("{$baseUrl}/usuario/sso/info/{$cpf}");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer {$serviceAccountToken}",
'APP: meu-app-private-label'
]
]);
$userInfo = json_decode(curl_exec($ch), true);
curl_close($ch);
import (
"encoding/json"
"fmt"
"net/http"
)
req, _ := http.NewRequest("GET", fmt.Sprintf("%s/usuario/sso/info/12345678909", baseUrl), nil)
req.Header.Set("Authorization", "Bearer "+serviceAccountToken)
req.Header.Set("APP", "meu-app-private-label")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
var userInfo map[string]interface{}
json.NewDecoder(resp.Body).Decode(&userInfo)
🎓 Recursos Adicionais
- 🔧 Guia de Troubleshooting — Solução de problemas e erros comuns
- 📄 Referência OpenAPI — Especificação técnica completa
🔒 Boas Práticas de Segurança
Armazenamento de Tokens
✅ FAZER:
- Use armazenamento seguro do sistema (Keychain/KeyStore)
- Criptografe tokens antes de armazenar
- Limpe tokens ao fazer logout
❌ NÃO FAZER:
- Armazenar em SharedPreferences/UserDefaults sem criptografia
- Armazenar em memória volátil
- Logar tokens em produção
Gestão de Credenciais
// ✅ CORRETO - Backend
const credentials = {
client_id: process.env.CLIENT_ID,
client_secret: process.env.CLIENT_SECRET
};
// ❌ ERRADO - Frontend
const credentials = {
client_secret: 'hardcoded-secret' // NUNCA FAÇA ISSO!
};
Implementação de Retry
async function loginWithRetry(username, password, maxRetries = 3) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const response = await login(username, password);
return response;
} catch (error) {
if (error.status === 401) {
throw new Error('Credenciais inválidas');
}
if (error.status === 429) {
// Rate limit - aguarde antes de tentar novamente
await sleep(Math.pow(2, attempt) * 1000);
continue;
}
if (error.status >= 500 && attempt < maxRetries) {
// Erro no servidor - tente novamente
await sleep(Math.pow(2, attempt) * 1000);
continue;
}
throw error;
}
}
}
⚠️ Tratamento de Erros
| Código | Status | Descrição | Ação Recomendada |
|---|---|---|---|
| 400 | ❌ Bad Request | Requisição inválida | Valide os parâmetros enviados |
| 401 | ❌ Unauthorized | Credenciais inválidas | Verifique usuário/senha |
| 403 | ❌ Forbidden | Acesso negado | Verifique permissões do cliente |
| 429 | ⚠️ Too Many Requests | Rate limit excedido | Aguarde e tente novamente |
| 500 | 🔥 Internal Server Error | Erro interno do servidor | Tente novamente em alguns segundos |
Exemplo de Resposta de Erro
{
"error": "invalid_grant",
"error_description": "Invalid user credentials",
"timestamp": "2025-12-03T10:30:00Z"
}
📚 Recursos Relacionados
- Primeiro Acesso - Cadastro de novos usuários
- Troca de Dispositivo - Autorizar novo dispositivo
- Recuperar Senha - Redefinir senha esquecida
- Autenticação OAuth 2.0