diff --git a/npm/ng-packs/apps/dev-app/src/server.ts b/npm/ng-packs/apps/dev-app/src/server.ts index b6ceaab1bc..94ce473445 100644 --- a/npm/ng-packs/apps/dev-app/src/server.ts +++ b/npm/ng-packs/apps/dev-app/src/server.ts @@ -5,9 +5,13 @@ import { writeResponseToNodeResponse, } from '@angular/ssr/node'; import express from 'express'; +import cookieParser from 'cookie-parser'; import { dirname, resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; +// ESM import +import * as oidc from 'openid-client'; + //TODO: Remove this line in production process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = "0"; @@ -29,6 +33,79 @@ const angularApp = new AngularNodeAppEngine(); * ``` */ +const ISSUER = new URL('https://localhost:44305/'); // OIDC issuer +const CLIENT_ID = 'MyProjectName_App'; +const REDIRECT_URI = 'http://localhost:4200'; // IdP'ye aynen kaydet +const SCOPE = 'offline_access MyProjectName'; + +const config = await oidc.discovery(ISSUER, CLIENT_ID, /* client_secret */ undefined); +const baseCookie = { httpOnly: false, sameSite: 'lax' as const, secure: false, path: '/' }; + +app.use(cookieParser()); + +const sessions = new Map(); + +app.get('/login', async (_req, res) => { + const code_verifier = oidc.randomPKCECodeVerifier(); + const code_challenge = await oidc.calculatePKCECodeChallenge(code_verifier); + const state = oidc.randomState(); + + const sid = crypto.randomUUID(); + sessions.set(sid, { pkce: code_verifier, state }); + res.cookie('sid', sid, baseCookie); + + const url = oidc.buildAuthorizationUrl(config, { + redirect_uri: REDIRECT_URI, + scope: SCOPE, + code_challenge, + code_challenge_method: 'S256', + state, + }); + res.redirect(url.toString()); +}); + +app.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'); + + // 👈 v6.6.4: metadata'ya böyle erişilir + const tokenEndpoint = config.serverMetadata().token_endpoint!; + // 👈 redirect_uri'yi SLASHSIZ gönderiyoruz (IdP kaydıyla birebir) + const body = new URLSearchParams({ + grant_type: 'authorization_code', + code: String(code), + redirect_uri: 'http://localhost:4200', + code_verifier: sess.pkce!, + client_id: CLIENT_ID, // public client + }); + + 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(); + console.log(tokens); + sessions.set(sid, { ...sess, at: tokens.access_token, refresh: tokens.refresh_token }); + return res.redirect('/'); + } catch (e) { + console.error('OIDC error:', e); + return res.status(500).send('oidc error'); + } +}); + /** * Serve static files from /browser */ diff --git a/npm/ng-packs/package.json b/npm/ng-packs/package.json index 4299790933..977e1e2817 100644 --- a/npm/ng-packs/package.json +++ b/npm/ng-packs/package.json @@ -144,5 +144,8 @@ "npx prettier --write --config .prettierrc " ] }, - "dependencies": {} + "dependencies": { + "cookie-parser": "^1.4.7", + "openid-client": "^6.6.4" + } }