Os clientes retomam o seu contexto de suporte sem expor um signing secret ou support API token ao navegador ou ao bundle da app.
Mantenha a assinatura no backend
O seu backend autentica o cliente, assina um JWT DobroDesk de curta duração para a integração e devolve-o por um endpoint protegido pela sessão do host. A resposta para os wrappers móveis é JSON com uma string authorizationToken.
O SDK não cria este JWT e loadDobroDeskToken é uma função fornecida pelo host. Nunca inclua signing secret, support API token ou credenciais longas no JavaScript, bundle móvel ou repositório público.
O widget web suporta sessão anónima. Os SDKs nativos exigem identidade assinada antes de operações de rede e apresentação. Os pedidos nativos usam Authorization: Bearer... com x-dobrodesk-client: native-v1, sem Origin do navegador. Depois do início, o motor envia a prova como x-dobrodesk-session-token e o host não deve criar ou substituir esse cabeçalho.
// This function belongs to your application. The route is your backend route.
async function loadDobroDeskToken(): Promise<string> {
const response = await fetch("/your-backend/dobrodesk-token", {
method: "POST",
credentials: "include",
headers: { Accept: "application/json" },
});
if (!response.ok) throw new Error("Customer token request failed");
const body = (await response.json()) as { authorizationToken?: unknown };
if (typeof body.authorizationToken !== "string" || !body.authorizationToken)
throw new Error("Customer token response is invalid");
return body.authorizationToken;
}
// Web can remain anonymous or apply the token after host login.
widget.setIdentityToken(await loadDobroDeskToken());
// React Native, NativeScript and Capacitor use the signed native shape.
const config = {
apiOrigin: "https://dobrodesk.com",
integrationId: "wgt_0123456789abcdef0123456789abcdef",
accountScope: currentCustomer.id,
credentialProvider: async () => ({
authorizationToken: await loadDobroDeskToken(),
}),
};Configurar o signing secret e os claims
Em Admin > Channels > Website widgets, abra a integração do widget, defina o identity mode como Require a signed logged-in user e use Copy identity secret. Guarde o secret específico da integração juntamente com o Integration ID público no gestor de segredos do backend. O secret nunca deve ficar no navegador, no bundle móvel ou num repositório público. Use-o como chave de assinatura HS256.
Assine um JWT HS256 de três partes com typ JWT. Claims obrigatórios: iss = dobrodesk-widget:{integrationId}, aud = Integration ID público, sub = ID estável do cliente que não seja email, iat = segundos Unix atuais e exp no máximo 15 minutos depois de iat. O verificador aceita 60 segundos de desvio. Claims opcionais: name, email, email_verified: true e jti. Defina email_verified apenas depois de verificar o endereço.
const textEncoder = new TextEncoder();
const base64url = (bytes: Uint8Array) => {
let binary = "";
for (const byte of bytes) binary += String.fromCharCode(byte);
return btoa(binary).replaceAll("+", "-").replaceAll("/", "_").replaceAll("=", "");
};
// secretStore is your backend secret manager. Never run this in browser code.
export async function createDobroDeskIdentityToken(user: {
id: string;
email?: string;
emailVerified?: boolean;
name?: string;
}) {
const integrationId = await secretStore.get("DOBRODESK_WIDGET_ID");
const identitySecret = await secretStore.get("DOBRODESK_WIDGET_IDENTITY_SECRET");
const now = Math.floor(Date.now() / 1000);
const encode = (value: unknown) =>
base64url(textEncoder.encode(JSON.stringify(value)));
const header = encode({ alg: "HS256", typ: "JWT" });
const payload = encode({
iss: `dobrodesk-widget:${integrationId}`,
aud: integrationId,
sub: user.id,
iat: now,
exp: now + 5 * 60,
...(user.email
? {
email: user.email,
...(user.emailVerified === true ? { email_verified: true } : {}),
}
: {}),
...(user.name ? { name: user.name } : {}),
});
const key = await crypto.subtle.importKey(
"raw",
textEncoder.encode(identitySecret),
{ name: "HMAC", hash: "SHA-256" },
false,
["sign"],
);
const signature = base64url(
new Uint8Array(
await crypto.subtle.sign("HMAC", key, textEncoder.encode(`${header}.${payload}`)),
),
);
return `${header}.${payload}.${signature}`;
}Associe e limpe a identidade deliberadamente
Use accountScope como identificador estável de cliente ou conta sem segredos. Ele isola a sessão nativa e a outbox. Não reutilize um scope para vários clientes.
Em Flutter, React Native, NativeScript ou Capacitor, chame logout antes de terminar a sessão ou mudar accountScope. Clientes iOS e Android diretos usam resetSession: reinicie o cliente e crie outro para a conta seguinte. Use resetSession quando o cliente descartar a conversa mas continuar ligado. Renovar o token não é trocar de conta.
Rejeite estados inseguros do token
- Rejeite token vazio, inválido, expirado ou de outro cliente no endpoint em vez de devolver uma credencial de suporte.
- Trate 401 ou session-expired como pedido de token novo para a mesma conta. Não troque accountScope nem crie sessão nova.
- Se logout ocorrer durante um pedido pendente, ignore o token tardio e isole a conta seguinte.