Browse Source

server.ts updated

pull/24026/head
erdemcaygor 3 months ago
parent
commit
d3be8ebffd
  1. 124
      npm/ng-packs/packages/schematics/src/commands/ssr-add/files/server-builder/server.ts.template

124
npm/ng-packs/packages/schematics/src/commands/ssr-add/files/server-builder/server.ts.template

@ -6,6 +6,17 @@ import express from 'express';
import { existsSync } from 'node:fs';
import { join } from 'node:path';
import <% if (isStandalone) { %>bootstrap<% } else { %>AppServerModule<% } %> from './main.server';
import {environment} from './environments/environment';
import * as oidc from 'openid-client';
const ISSUER = new URL(environment.oAuthConfig.issuer);
const CLIENT_ID = environment.oAuthConfig.clientId;
const REDIRECT_URI = environment.oAuthConfig.redirectUri;
const SCOPE = environment.oAuthConfig.scope;
const config = await oidc.discovery(ISSUER, CLIENT_ID, /* client_secret */ undefined);
const secureCookie = { httpOnly: true, sameSite: 'lax' as const, secure: environment.production, path: '/' };
const tokenCookie = { ...secureCookie, httpOnly: false };
// The Express app is exported so that it can be used by serverless Functions.
export function app(): express.Express {
@ -20,6 +31,119 @@ export function app(): express.Express {
server.set('view engine', 'html');
server.set('views', distFolder);
server.use(ServerCookieParser.middleware());
const sessions = new Map<string, { pkce?: string; state?: string; refresh?: string; at?: string, returnUrl?: string }>();
server.get('/authorize', async (_req, res) => {
const code_verifier = oidc.randomPKCECodeVerifier();
const code_challenge = await oidc.calculatePKCECodeChallenge(code_verifier);
const state = oidc.randomState();
if (_req.query.returnUrl) {
const returnUrl = String(_req.query.returnUrl || null);
res.cookie('returnUrl', returnUrl, { ...secureCookie, maxAge: 5 * 60 * 1000 });
}
const sid = crypto.randomUUID();
sessions.set(sid, { pkce: code_verifier, state });
res.cookie('sid', sid, secureCookie);
const url = oidc.buildAuthorizationUrl(config, {
redirect_uri: REDIRECT_URI,
scope: SCOPE,
code_challenge,
code_challenge_method: 'S256',
state,
});
res.redirect(url.toString());
});
server.get('/logout', async (req, res) => {
try {
const sid = req.cookies.sid;
if (sid && sessions.has(sid)) {
sessions.delete(sid);
}
res.clearCookie('sid', secureCookie);
res.clearCookie('access_token', tokenCookie);
res.clearCookie('refresh_token', secureCookie);
res.clearCookie('expires_at', tokenCookie);
res.clearCookie('returnUrl', secureCookie);
const endSessionEndpoint = config.serverMetadata().end_session_endpoint;
if (endSessionEndpoint) {
const logoutUrl = new URL(endSessionEndpoint);
logoutUrl.searchParams.set('post_logout_redirect_uri', REDIRECT_URI);
logoutUrl.searchParams.set('client_id', CLIENT_ID);
return res.redirect(logoutUrl.toString());
}
res.redirect('/');
} catch (error) {
console.error('Logout error:', error);
res.status(500).send('Logout error');
}
});
server.get('/', async (req, res, next) => {
try {
const { code, state } = req.query as any;
if (!code || !state) return next();
const sid = req.cookies.sid;
const sess = sid && sessions.get(sid);
if (!sess || state !== sess.state) return res.status(400).send('invalid state');
const tokenEndpoint = config.serverMetadata().token_endpoint!;
const body = new URLSearchParams({
grant_type: 'authorization_code',
code: String(code),
redirect_uri: environment.oAuthConfig.redirectUri,
code_verifier: sess.pkce!,
client_id: CLIENT_ID
});
const resp = await fetch(tokenEndpoint, {
method: 'POST',
headers: { 'content-type': 'application/x-www-form-urlencoded' },
body,
});
if (!resp.ok) {
const errTxt = await resp.text();
console.error('token error:', resp.status, errTxt);
return res.status(500).send('token error');
}
const tokens = await resp.json();
const expiresInSec =
Number(tokens.expires_in ?? tokens.expiresIn ?? 3600);
const skewSec = 60;
const accessExpiresAt = new Date(
Date.now() + Math.max(0, expiresInSec - skewSec) * 1000
);
sessions.set(sid, { ...sess, at: tokens.access_token, refresh: tokens.refresh_token });
res.cookie('access_token', tokens.access_token, {...tokenCookie, maxAge: accessExpiresAt.getTime()});
res.cookie('refresh_token', tokens.refresh_token, secureCookie);
res.cookie('expires_at', String(accessExpiresAt.getTime()), tokenCookie);
const returnUrl = req.cookies?.returnUrl ?? '/';
res.clearCookie('returnUrl', secureCookie);
return res.redirect(returnUrl);
} catch (e) {
console.error('OIDC error:', e);
return res.status(500).send('oidc error');
}
});
// Example Express Rest API endpoints
// server.get('/api/{*splat}', (req, res) => { });
// Serve static files from /browser

Loading…
Cancel
Save