Após concluir a configuração do JWT no Document360, sua aplicação precisa de uma rota backend para lidar com a etapa final do fluxo de login.
Esta rota:
- Valida que o usuário já está autenticado na sua aplicação
- Envia uma requisição segura para a URL de geração de código do Document360
- Recupera um código de autorização de uso único
- Redireciona o usuário para o site da base de conhecimento com esse código
Leitores não precisam de uma conta separada no Document360. A autenticação é feita inteiramente pelo seu aplicativo. Uma conta no seu aplicativo é suficiente para que um leitor acesse a base de conhecimento.
Exemplos de código
Os exemplos abaixo mostram como implementar a rota de autenticação backend em C#, Node.js e Java.
C#
/// <summary>
/// Example endpoint to authenticate a user and retrieve a token from the identity server,
/// and redirect the user to the Knowledge Base (KB) using the token code.
/// </summary>
/// <param name="clientId">Client ID issued for your application</param>
/// <param name="clientSecret">Client secret associated with the client ID</param>
/// <returns>Redirects to the KB with the issued code</returns>
[HttpGet]
[Route("authenticate")]
public async Task<IActionResult> AuthenticateAsync(string clientId, string clientSecret)
{
if (!HttpContext.User.Identity.IsAuthenticated)
{
// user is not authenticated, redirect to an error or login page
return Unauthorized(new { message = "User not authenticated" });
}
// Ensure you have the correct client ID and secret from your Document360 JWT configuration
var authToken = Encoding.ASCII.GetBytes($"{clientId}:{clientSecret}");
// Create an HttpClient instance
using var httpClient = new HttpClient();
// Set the Authorization header with Basic authentication
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(authToken));
// Prepare the payload with user information
var payload = new
{
username = User.Identity.Name,
firstName = "FirstName", // Replace or customize as needed
lastName = "LastName",
emailId = "user@example.com", // Replace with actual user email
readerGroupIds = new List<string> { "group1", "group2" }, // Replace with actual reader group IDs if needed (Optional)
tokenValidity = 3600 // Token validity in seconds (Optional, default is 5 minutes)
};
var payloadContent = new StringContent(JsonConvert.SerializeObject(payload), Encoding.UTF8, "application/json");
// Identity server token endpoint - replace with your actual URL
string identityServerUrl = "codeGeneration endpoint, you can find that in JWT config portal";
// KB login URL to redirect after successful token issuance
string kbLoginUrl = "https://{your subdomain}.document360.io";
var response = await httpClient.PostAsync(identityServerUrl, payloadContent);
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync();
var tokenJson = JObject.Parse(content);
// Extract the code from the response
var tokenCode = (string)tokenJson.SelectToken("code");
// Construct the KB login URL with code query parameter
string finalRedirectUrl = $"{kbLoginUrl}?code={tokenCode}";
return Redirect(finalRedirectUrl);
}
else
{
// Handle error response from the identity server
var error = await response.Content.ReadAsStringAsync();
return StatusCode((int)response.StatusCode, new { error = "Token request failed", details = error });
}
}
Node.js
const express = require('express');
const https = require('https');
const axios = require('axios');
const app = express();
app.use(express.json());
const clientId = 'your-client-id';
const clientSecret = 'your-client-secret';
const codeGenerationUrl = 'https://identity.document360.net/jwt/generateCode';
const kbLoginUrl = 'https://your-subdomain.document360.net/jwt/authorize';
app.get('/authenticate', async (req, res) => {
try {
const isAuthenticated = true; // Replace with your actual auth logic
if (!isAuthenticated) {
return res.status(401).json({ message: 'User not authenticated' });
}
const authHeader = Buffer.from(`${clientId}:${clientSecret}`).toString('base64');
const payload = {
username: 'john.doe',
firstName: 'John',
lastName: 'Doe',
emailId: 'john.doe@example.com',
readerGroupIds: ['group1', 'group2'],
tokenValidity: 3600
};
const response = await axios.post(
codeGenerationUrl,
payload,
{
headers: {
'Authorization': `Basic ${authHeader}`,
'Content-Type': 'application/json',
'Accept': 'application/json'
},
httpsAgent: new https.Agent({ maxVersion: 'TLSv1.2' })
}
);
const tokenCode = response.data?.code;
if (!tokenCode) {
return res.status(500).json({ message: 'No code received from Document360' });
}
console.log("Redirecting to:", `${kbLoginUrl}?code=${tokenCode}`);
return res.redirect(`${kbLoginUrl}?code=${tokenCode}`);
} catch (error) {
return res.status(500).json({
message: 'JWT SSO failed',
details: error.response?.data || error.message
});
}
});
Java
import org.springframework.http.*;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;
import java.nio.charset.StandardCharsets;
import java.util.*;
@RestController
public class JwtSsoController {
private final String clientId = "your-client-id";
private final String clientSecret = "your-client-secret";
private final String codeGenerationUrl = "https://identity.document360.io/api/jwt/generate-code";
private final String kbLoginUrl = "https://your-subdomain.document360.io/jwt/authorize";
@GetMapping("/authenticate")
public ResponseEntity<?> authenticate() {
// Example: Check if user is authenticated in your system
boolean isAuthenticated = true; // Replace with actual logic
if (!isAuthenticated) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("User not authenticated");
}
// Create Basic Auth header
String auth = clientId + ":" + clientSecret;
String encodedAuth = Base64.getEncoder().encodeToString(auth.getBytes(StandardCharsets.UTF_8));
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("Authorization", "Basic " + encodedAuth);
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
// Construct payload
Map<String, Object> payload = new HashMap<>();
payload.put("username", "john.doe");
payload.put("firstName", "John");
payload.put("lastName", "Doe");
payload.put("emailId", "john.doe@example.com");
payload.put("readerGroupIds", Arrays.asList("group1", "group2"));
payload.put("tokenValidity", 3600);
HttpEntity<Map<String, Object>> request = new HttpEntity<>(payload, headers);
RestTemplate restTemplate = new RestTemplate();
try {
ResponseEntity<Map> response = restTemplate.postForEntity(codeGenerationUrl, request, Map.class);
if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
String tokenCode = (String) response.getBody().get("code");
if (tokenCode == null || tokenCode.isEmpty()) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("No code returned from Document360");
}
// Redirect to the KB site with code
String redirectUrl = UriComponentsBuilder.fromHttpUrl(kbLoginUrl)
.queryParam("code", tokenCode)
.toUriString();
HttpHeaders redirectHeaders = new HttpHeaders();
redirectHeaders.setLocation(java.net.URI.create(redirectUrl));
return new ResponseEntity<>(redirectHeaders, HttpStatus.FOUND);
} else {
return ResponseEntity.status(HttpStatus.BAD_GATEWAY)
.body("Failed to get code from Document360: " + response.getStatusCode());
}
} catch (Exception ex) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("JWT SSO error: " + ex.getMessage());
}
}
}
Lista de verificação para desenvolvedores
Antes de entrar no ar, verifique o seguinte:
- Registre a URL de login, a URL de retorno de chamada e a URL de geração de código nas configurações do seu JWT.
- Armazene o Segredo do Cliente de forma segura. Ele é exibido apenas uma vez no momento da criação.
- Implemente lógica backend para chamar a URL de geração de código usando HTTP Basic Auth.
- Assine o JWT no seu backend usando seu segredo de cliente. Nunca expõe a lógica de assinatura do lado do cliente.
- Aplique o HTTPS em todos os endpoints envolvidos no fluxo de autenticação.
- Teste comportamento da sessão, vencimento do token e renovação automática da sessão antes de entrar no ar.
- Monitore os logs backend para erros 401, que normalmente indicam códigos de autorização expirados ou incompatibilidades de tokens.
Redirecionar para uma página específica após o login
Por padrão, após fazer login, os leitores são redirecionados para a página inicial da sua base de conhecimento.
- Se sua página inicial não for publicada, os leitores são redirecionados para a
/docspágina. - Para redirecionar os leitores para uma página diferente na sua base de conhecimento, configure o redirecionamento usando o seguinte padrão de URL.
Padrão URL
https://<Knowledge base URL>/jwt/authorize?code=<code>&redirectUrl=<redirect path>
Parâmetros
<Knowledge base URL>: a URL principal do seu site de base de conhecimento.<code>: o código gerado pelo endpoint de geração de código Document360.<redirect path>: a URL onde você quer que os leitores cheguem após o login.
Exemplo
https://example.document360.io/jwt/authorize?code=FOTaS_SW6dLGytQXvrG_rRFGhyPvrDDrgxJAZzYvJcY&redirectUrl=/docs/5-basic-things-to-get-started
O Document360 enviará a URL de Redirecionamento para redirectPath o endpoint de login. Quando o endpoint de login redireciona de volta para a base de conhecimento com o código de autenticação, ele deve retornar a URL de Redirecionamento como parâmetro redirectUrl .
No KB Site 2.0, o redirecionamento é feito usando cookies em vez do redirectUrl parâmetro. Se sua implementação no JWT for baseada em redirecionamento de strings de consulta usando o redirectUrl parâmetro, a abordagem baseada em cookies não suporta esse parâmetro. Talvez você precise atualizar sua implementação ou entrar em contato com o suporte para esclarecimentos adicionais.