@policiarcc/rccsystem-atlas-oidc-express
v0.1.3
Published
Handlers OIDC do RCCSystem Atlas para Express.
Readme
@policiarcc/rccsystem-atlas-oidc-express
Handlers de Login com o RCCSystem para Express. O pacote entrega auth.login e auth.callback; sua aplicação configura a sessão persistente, cria o principal local e aplica as permissões do produto.
Antes de começar
No Atlas, crie um app Web confidencial e registre:
http://localhost:3000/auth/callback
https://portal.parceiro.com/auth/callbackHabilite openid profile_basic profile_rcc groups group_roles caso o produto autorize por cargo/grupo. clientSecret nunca vai ao browser.
npm install express express-session connect-redis redis \
@policiarcc/rccsystem-atlas-oidc \
@policiarcc/rccsystem-atlas-oidc-expressNão use o MemoryStore padrão de express-session em produção: use Redis, banco ou outro store compartilhado.
Configure cliente e sessão
import { createAtlasServer } from "@policiarcc/rccsystem-atlas-oidc/server";
export const atlas = createAtlasServer({
issuer: process.env.ATLAS_OIDC_ISSUER!,
clientId: process.env.ATLAS_OIDC_CLIENT_ID!,
clientSecret: process.env.ATLAS_OIDC_CLIENT_SECRET!,
redirectUri: `${process.env.APP_URL}/auth/callback`,
scopes: ["openid", "profile_basic", "profile_rcc", "groups", "group_roles"],
});import express from "express";
import session from "express-session";
const app = express();
app.set("trust proxy", 1);
app.use(
session({
name:
process.env.NODE_ENV === "production"
? "__Host-partner-session"
: "partner-session",
store: redisStore,
secret: process.env.SESSION_SECRET!,
resave: false,
saveUninitialized: false,
cookie: {
httpOnly: true,
secure: process.env.NODE_ENV === "production",
sameSite: "lax",
path: "/",
},
}),
);Com Nginx, Cloudflare ou load balancer, trust proxy é necessário para cookies Secure funcionarem. Em HTTPS, __Host- também requer Path=/ e nenhum Domain.
Monte as rotas OIDC
import { createAtlasExpressAuth } from "@policiarcc/rccsystem-atlas-oidc-express";
import { atlas } from "./atlas.js";
export const auth = createAtlasExpressAuth({
atlas,
async onAuthenticated({ identity, entitlement, req }) {
const request = req as { session: Record<string, unknown> };
const access = buildAccessFromGroupRoles(entitlement.groupRoles);
if (!access) throw new Error("PARTNER_ACCESS_DENIED");
const principal = await db.principal.upsert({
where: { oidcSubject: identity.subject },
create: {
oidcSubject: identity.subject,
username: entitlement.username ?? "Sem nick",
},
update: { username: entitlement.username ?? "Sem nick" },
});
request.session.principalId = principal.id;
request.session.oidcSubject = identity.subject;
},
});app.get(
"/auth/login",
(req, res, next) => void auth.login(req, res).catch(next),
);
app.get(
"/auth/callback",
(req, res, next) => void auth.callback(req, res).catch(next),
);O adaptador guarda state, nonce e PKCE na sessão temporária, consome-a no callback e chama requireEntitlement() antes de onAuthenticated. Não guarde token do Atlas na sessão do Express.
Proteja as rotas de negócio
import { AtlasOidcError } from "@policiarcc/rccsystem-atlas-oidc";
export async function requireAccess(req, res, next) {
const subject = req.session.oidcSubject;
if (typeof subject !== "string") return res.redirect("/login");
try {
res.locals.entitlement = await atlas.requireEntitlement(subject);
return next();
} catch (error) {
if (
error instanceof AtlasOidcError &&
error.code === "ATLAS_ENTITLEMENT_INACTIVE"
) {
return req.session.destroy(() => res.redirect("/acesso-negado"));
}
return res.status(503).render("indisponivel");
}
}
app.get("/admin", requireAccess, (req, res) => {
if (!buildAccessFromGroupRoles(res.locals.entitlement.groupRoles).canAdmin)
return res.sendStatus(403);
res.render("admin");
});Revalide no servidor em toda página e mutação protegida. Sem confirmação do Atlas, responda 503; nunca permita acesso com roles de sessão antigas.
Logout e segurança
app.post("/auth/logout", requireCsrf, (req, res, next) => {
req.session.destroy((error) => {
if (error) return next(error);
res.clearCookie("__Host-partner-session", { path: "/" });
res.redirect("/");
});
});- Use CSRF e valide
OriginemPOST,PATCH,PUTeDELETE. - Não registre URL completa do callback, cabeçalho
Authorization, código ou token. ATLAS_LOGIN_INVALIDpede reinício do login;ATLAS_ENTITLEMENT_INACTIVErevoga sessão; indisponibilidade vira503.
Documentação completa: SDK para Express.
