Aprenda a incorporar dashboards do Oracle Analytics Cloud em um site público sem expor senhas, client secrets ou tokens estáticos. Neste guia, vou apresentar uma integração segura com OCI Vault, Oracle Functions e API Gateway. Para exibir um dashboard do Oracle Analytics Cloud (OAC) dentro de um portal sem pedir login ao visitante, a página não pode conter senha, client secret nem token fixo. Esses dados ficam na Oracle Cloud Infrastructure (OCI), e o navegador recebe somente um access token temporário, mantido em memória e válido por pouco tempo.
Com esse objetivo, nossa página pública deve solicitar um token ao API Gateway. O Gateway chama uma Oracle Function, que recupera os segredos no OCI Vault e pede o token ao Identity Domain. O token representa um usuário técnico com acesso mínimo ao workbook no OAC.
Arquitetura recomendada
A solução separa a exibição do dashboard da emissão de credenciais temporárias.
- O visitante acessa uma página web com o dashboard incorporado.
- A página solicita um token temporário a um endpoint controlado.
- O API Gateway encaminha a solicitação para uma Oracle Function.
- A Function obtém segredos protegidos no OCI Vault.
- A Function solicita um access token ao Identity Domain.
- O navegador recebe somente o token temporário necessário para carregar o conteúdo.
- O OAC aplica as permissões associadas ao usuário técnico configurado.

Antes de começar
- Tenha acesso ao OAC, ao Identity Domain e ao compartment OCI em que os recursos serão criados.
- Tenha um workbook publicado no OAC e defina quais dados poderão ser exibidos.
- Use um ambiente de homologação para o primeiro teste, sempre que possível.
- Crie um usuário técnico exclusivo, com permissão somente de leitura.
Os nomes a seguir são exemplos. Substitua todos os valores entre <...> pelos dados do seu ambiente.
<COMPARTMENT> Exemplo: ambiente-analytics
<USUARIO_TECNICO> Exemplo: usuario.dashboard@exemplo.com
<HOST_OAC> Exemplo: analytics.exemplo.oraclecloud.com
<HOST_GATEWAY> Host mostrado pelo API Gateway
<PROJECT_PATH> Caminho copiado da opção Embed do workbook
1. Criar e preparar o usuário técnico
No Console OCI, acesse Identity & Security → Domains → Users. Crie ou selecione um usuário técnico, preencha e-mail, nome e sobrenome e confirme que a conta está ativa.
Depois, entre no OAC com esse usuário e conceda acesso de visualização somente à pasta e ao workbook que serão incorporados. Faça um teste: ele deve abrir o workbook diretamente no OAC. O token não cria permissões novas; ele usa exatamente os acessos desse usuário.
2. Criar a aplicação OAuth
No Console OCI, acesse Identity & Security → Domains → <SEU_DOMAIN> → Integrated applications. Crie uma Confidential Application, por exemplo app-dashboard-token.
- Ative a aplicação após criá-la.
- Na aba OAuth configuration, habilite OAuth.
- Habilite o fluxo de autenticação aprovado para o seu ambiente, como Resource Owner quando aplicável.
- Selecione o recurso do Analytics e copie o scope apresentado.
- Registre a URL do token, o Client ID e o Client Secret.
A Function precisará destes valores não secretos:
IDCS_TOKEN_URL=https://<SEU_DOMAIN>.identity.oraclecloud.com/oauth2/v1/token
OAC_CLIENT_ID=<CLIENT_ID_DA_APLICACAO>
OAC_SCOPE=<SCOPE_DO_RECURSO_ANALYTICS>
OAC_USERNAME=<USUARIO_TECNICO>
O client secret e a senha do usuário técnico também serão necessários, mas ficarão no Vault, nunca no HTML ou no repositório.
3. Autorizar o domínio do portal no OAC
No OAC, acesse Navigator → Console → Safe Domains. Adicione a origem do site que exibirá o dashboard e marque Embedding.
Informe a origem exata, com protocolo e porta. Para teste local: http://127.0.0.1:5500. Para produção: https://portal.exemplo.com. Não inclua index.html nem outro caminho na origem cadastrada.

4. Copiar as informações do workbook
Abra o workbook no OAC em modo de edição e localize a opção Embed. Copie o project-path, o active-page e o active-tab-id. Esses valores identificam o conteúdo que será carregado.
<oracle-dv
project-path="<PROJECT_PATH>"
active-page="<ACTIVE_PAGE>"
active-tab-id="<ACTIVE_TAB_ID>">
</oracle-dv>
5. Guardar os segredos no OCI Vault
No Console OCI, acesse Identity & Security → Vault. Crie ou reutilize um Vault e uma chave mestra. Em Secrets, crie dois secrets separados:
secret-dashboard-client-secret: contém o client secret OAuth.secret-dashboard-user-password: contém a senha do usuário técnico.
Após criá-los, copie apenas os OCIDs dos secrets. O OCID é uma referência que pode ser usada na configuração da Function; o conteúdo secreto não deve aparecer em arquivos, variáveis abertas ou logs.
6. Criar a Oracle Function de token
Em Developer Services → Functions, crie uma Application e uma Function, por exemplo fn-dashboard-token. A Function deve recuperar os dois secrets no Vault usando Resource Principal, chamar a URL OAuth e responder um JSON com access_token, token_type e expires_in.
A Application da Function deve ter saída HTTPS para o OCI Vault e o Identity Domain. Se ela estiver em uma subnet privada, configure uma rota 0.0.0.0/0 para um NAT Gateway e uma regra de saída TCP na porta 443. Sem essa conectividade, a Function não conseguirá ler os secrets nem solicitar o token.
Na aba Configuration da Function, informe apenas valores não secretos e OCIDs:
IDCS_TOKEN_URL=https://<SEU_DOMAIN>.identity.oraclecloud.com/oauth2/v1/token
OAC_CLIENT_ID=<CLIENT_ID_DA_APLICACAO>
OAC_SCOPE=<SCOPE_DO_RECURSO_ANALYTICS>
OAC_USERNAME=<USUARIO_TECNICO>
OAC_CLIENT_SECRET_SECRET_OCID=<OCID_DO_SECRET_CLIENT_SECRET>
OAC_USER_PASSWORD_SECRET_OCID=<OCID_DO_SECRET_SENHA>
OAC_TOKEN_EXPIRY_SECONDS=300
OAC_TOKEN_EXPIRY_SECONDS é opcional e define, em segundos, a validade solicitada para o token; use um valor inteiro de pelo menos 60, como 300. Não use variáveis como OAC_CLIENT_SECRET ou OAC_USER_PASSWORD com valores reais. A leitura deve acontecer apenas em memória, durante a execução da Function.
Código da Function (func.js)
Substitua o conteúdo padrão da Function pelo código abaixo. Ele usa o Resource Principal para ler os dois secrets no OCI Vault, sem gravar senha, client secret ou token nos logs.
const fdk = require('@fnproject/fdk');
const fetch = require('node-fetch');
const common = require('oci-common');
const secrets = require('oci-secrets');
async function getSecretValue(secretsClient, secretId) {
const response = await secretsClient.getSecretBundle({ secretId });
const encodedValue =
response.secretBundle.secretBundleContent.content;
if (!encodedValue) {
throw new Error('Vault returned an empty secret bundle.');
}
return Buffer.from(encodedValue, 'base64').toString('utf8');
}
fdk.handle(async () => {
const required = [
'IDCS_TOKEN_URL',
'OAC_SCOPE',
'OAC_USERNAME',
'OAC_CLIENT_ID',
'OAC_CLIENT_SECRET_SECRET_OCID',
'OAC_USER_PASSWORD_SECRET_OCID'
];
const missing = required.filter((key) => !process.env[key]);
if (missing.length) {
console.error(`Missing configuration: ${missing.join(', ')}`);
return { error: 'Function configuration is incomplete.' };
}
const tokenExpirySeconds = process.env.OAC_TOKEN_EXPIRY_SECONDS;
if (
tokenExpirySeconds &&
(!/^\d+$/.test(tokenExpirySeconds) || Number(tokenExpirySeconds) < 60)
) {
console.error('OAC_TOKEN_EXPIRY_SECONDS must be an integer of at least 60.');
return { error: 'Token expiration configuration is invalid.' };
}
try {
const provider =
await common.ResourcePrincipalAuthenticationDetailsProvider.builder();
const secretsClient = new secrets.SecretsClient({
authenticationDetailsProvider: provider
});
const [clientSecret, userPassword] = await Promise.all([
getSecretValue(
secretsClient,
process.env.OAC_CLIENT_SECRET_SECRET_OCID
),
getSecretValue(
secretsClient,
process.env.OAC_USER_PASSWORD_SECRET_OCID
)
]);
const tokenExpiryScope = tokenExpirySeconds
? ` urn:opc:resource:expiry=${tokenExpirySeconds}`
: '';
const form = new URLSearchParams({
grant_type: 'password',
username: process.env.OAC_USERNAME,
password: userPassword,
scope: `${process.env.OAC_SCOPE}${tokenExpiryScope}`
});
const basicAuth = Buffer.from(
`${process.env.OAC_CLIENT_ID}:${clientSecret}`
).toString('base64');
const response = await fetch(process.env.IDCS_TOKEN_URL, {
method: 'POST',
headers: {
Authorization: `Basic ${basicAuth}`,
'Content-Type':
'application/x-www-form-urlencoded;charset=UTF-8'
},
body: form.toString()
});
const data = await response.json();
if (!response.ok) {
console.error(
`Identity Domain returned HTTP ${response.status}: ${data.error}`
);
return { error: 'Unable to generate OAC token.' };
}
return {
access_token: data.access_token,
token_type: data.token_type,
expires_in: data.expires_in
};
} catch {
console.error('Token service failed.');
return { error: 'Token service is unavailable.' };
}
});
No package.json, preserve os demais campos criados pelo template e inclua as dependências oci-common e oci-secrets, além de @fnproject/fdk e node-fetch.
{
"dependencies": {
"@fnproject/fdk": "^0.0.72",
"node-fetch": "^2.6.12",
"oci-common": "^2.137.1",
"oci-secrets": "^2.137.1"
}
}
Salve func.js e package.json e publique a nova imagem da Function. Editar os arquivos no Code Editor não atualiza a Function em execução.
fn -v deploy --app <NOME_DA_APPLICATION>
7. Permitir que a Function leia somente os secrets necessários
Crie um Dynamic Group em Identity & Security → Domains → <SEU_DOMAIN> → Dynamic Groups, restrito à Function criada. Depois, em Identity & Security → Policies, crie uma policy que permita a leitura apenas dos dois secrets usados pela Function.
Nome: dg-fn-dashboard-token-vault
Matching rule:
resource.id = '<OCID_DA_FUNCTION>'
Exemplo conceitual; substitua os marcadores:
Allow dynamic-group <DYNAMIC_GROUP_DA_FUNCTION>
to read secret-bundles in compartment <COMPARTMENT>
where target.secret.id = '<OCID_DO_SECRET_CLIENT_SECRET>'
Allow dynamic-group <DYNAMIC_GROUP_DA_FUNCTION>
to read secret-bundles in compartment <COMPARTMENT>
where target.secret.id = '<OCID_DO_SECRET_SENHA>'
Dynamic Groups e policies podem levar alguns minutos para propagar. Se a Function falhar ao ler o Vault logo após a mudança, aguarde antes de alterar o código.
8. Publicar a Function no API Gateway
Em Identity & Security → Policies, crie antes uma policy que permita ao API Gateway invocar Functions:
ALLOW any-user to use functions-family in compartment <COMPARTMENT>
where ALL {
request.principal.type = 'ApiGateway',
request.resource.compartment.id = '<OCID_DO_COMPARTMENT>'
}
Depois, acesse Developer Services → API Gateway → Gateways e crie um Gateway público. Quando ele estiver ativo, abra Deployments e crie uma rota com estes valores:
- Path prefix:
/dashboard-publico - Route path:
/token - Method:
GET - Backend type: Oracle Functions
- Backend: a Application e a Function criadas na etapa anterior
A URL final ficará semelhante a https://<HOST_GATEWAY>/dashboard-publico/token. No CORS, autorize somente a origem do portal, por exemplo https://portal.exemplo.com, e permita GET. Configure também rate limiting no nível do deployment — não é configurado por rota — usando a chave CLIENT_IP e um limite inicial compatível com o volume esperado, por exemplo 5 a 10 requisições por segundo.
9. Inserir o código na página que exibirá o dashboard
Este exemplo carrega o framework do OAC, obtém um token do Gateway e o entrega ao componente. Substitua todos os marcadores antes de publicar.
<script
src="https://<HOST_OAC>/public/dv/v1/embedding/standalone/embedding.js?TOKEN=true"
type="application/javascript">
</script>
<oracle-dv
project-path="<PROJECT_PATH>"
active-page="<ACTIVE_PAGE>"
active-tab-id="<ACTIVE_TAB_ID>">
</oracle-dv>
<script>
const gatewayTokenUrl =
'https://<HOST_GATEWAY>/dashboard-publico/token';
async function getOacToken() {
const response = await fetch(gatewayTokenUrl, {
method: 'GET',
cache: 'no-store'
});
if (!response.ok) {
throw new Error(`Falha ao obter token: ${response.status}`);
}
const data = await response.json();
if (!data.access_token) {
throw new Error('A resposta não contém access_token.');
}
return data.access_token;
}
async function initializeOac() {
const token = await getOacToken();
requirejs([
'jquery', 'knockout', 'obitech-application/application',
'ojs/ojcore', 'ojs/ojknockout', 'ojs/ojcomposite',
'jet-composites/oracle-dv/loader'
], function ($, ko, application) {
application.setSecurityConfig('token', {
tokenAuthFunction: function () {
return token;
}
});
ko.applyBindings();
});
}
initializeOac().catch(console.error);
</script>
tokenAuthFunction deve retornar uma string, não uma Promise. Por isso, o exemplo busca o token antes de configurar o componente.
10. Validar antes de publicar
- Abra a página por HTTP ou HTTPS; não use
file://. - Confirme que o workbook aparece sem tela de login.
- Verifique se o domínio está cadastrado tanto em Safe Domains quanto no CORS.
- Teste filtros e visualizações com as permissões do usuário técnico.
- Confirme que HTML, repositório e logs não contêm senha, client secret ou token real.
- Se houver erro 401, 403 ou 5xx, valide Function, policy do Gateway, usuário técnico e OAuth nessa ordem.
