add .well-known routes for openid connect protocol, show jwks.json and openid-configuration

This commit is contained in:
einhornimmond 2025-07-20 08:46:47 +02:00
parent d4683ce1d7
commit 80903243df
6 changed files with 110 additions and 0 deletions

View File

@ -1 +1,2 @@
export const LOG4JS_BASE_CATEGORY_NAME = 'backend'
export const FRONTEND_LOGIN_ROUTE = 'login'

View File

@ -0,0 +1,55 @@
import { CONFIG } from '@/config'
import { FRONTEND_LOGIN_ROUTE, LOG4JS_BASE_CATEGORY_NAME } from '@/config/const'
import { getHomeCommunity } from 'database'
import { importSPKI, exportJWK } from 'jose'
import { createHash } from 'crypto'
import { getLogger } from 'log4js'
const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.openIDConnect`)
const defaultErrorForCaller = 'Internal Server Error'
export const openidConfiguration = async (req: any, res: any): Promise<void> => {
res.setHeader('Content-Type', 'application/json')
res.status(200).json({
issuer: new URL(FRONTEND_LOGIN_ROUTE, CONFIG.COMMUNITY_URL).toString(),
jwks_uri: new URL('/.well-known/jwks.json', CONFIG.COMMUNITY_URL).toString(),
})
}
export const jwks = async (req: any, res: any): Promise<void> => {
const homeCommunity = await getHomeCommunity()
if (!homeCommunity) {
logger.error('HomeCommunity not found')
throw new Error(defaultErrorForCaller)
}
if (!homeCommunity.publicJwtKey) {
logger.error('HomeCommunity publicJwtKey not found')
throw new Error(defaultErrorForCaller)
}
try {
const publicKey = await importSPKI(homeCommunity.publicJwtKey, 'RS256')
const jwk = await exportJWK(publicKey)
// Optional: calculate Key ID (z.B. SHA-256 Fingerprint)
const kid = createHash('sha256')
.update(homeCommunity.publicJwtKey)
.digest('base64url')
const jwks = {
keys: [
{
...jwk,
alg: 'RS256',
use: 'sig',
kid,
},
],
}
res.setHeader('Cache-Control', 'public, max-age=3600, immutable')
res.setHeader('Content-Type', 'application/json')
res.status(200).json(jwks)
} catch (err) {
logger.error('Failed to convert publicJwtKey to JWK', err)
res.status(500).json({ error: 'Failed to generate JWKS' })
}
}

View File

@ -15,6 +15,7 @@ import { context as serverContext } from './context'
import { cors } from './cors'
import { i18n } from './localization'
import { plugins } from './plugins'
import { jwks, openidConfiguration } from '@/openIDConnect'
// TODO implement
// import queryComplexity, { simpleEstimator, fieldConfigEstimator } from "graphql-query-complexity";
@ -84,6 +85,10 @@ export const createServer = async (
app.get('/hook/gms/' + CONFIG.GMS_WEBHOOK_SECRET, gmsWebhook)
// OpenID Connect
app.get('/.well-known/openid-configuration', openidConfiguration)
app.get('/.well-known/jwks.json', jwks)
// Apollo Server
const apollo = new ApolloServer({
schema: await schema(),

View File

@ -129,6 +129,24 @@ server {
error_log $GRADIDO_LOG_PATH/nginx-error.hooks.log warn;
}
# Well-Known for openid connect
location /.well-known/ {
limit_req zone=backend burst=20 nodelay;
limit_conn addr 10;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_pass http://127.0.0.1:4000/.well-known/;
proxy_redirect off;
access_log $GRADIDO_LOG_PATH/nginx-access.well-known.log gradido_log;
error_log $GRADIDO_LOG_PATH/nginx-error.well-known.log warn;
}
# Admin Frontend
location /admin {
limit_req zone=frontend burst=30 nodelay;

View File

@ -114,6 +114,24 @@ server {
error_log $GRADIDO_LOG_PATH/nginx-error.hooks.log warn;
}
# Well-Known for openid connect
location /.well-known/ {
limit_req zone=backend burst=20 nodelay;
limit_conn addr 10;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_pass http://127.0.0.1:4000/.well-known/;
proxy_redirect off;
access_log $GRADIDO_LOG_PATH/nginx-access.well-known.log gradido_log;
error_log $GRADIDO_LOG_PATH/nginx-error.well-known.log warn;
}
# Admin Frontend
location /admin {
limit_req zone=frontend burst=30 nodelay;

View File

@ -43,6 +43,19 @@ server {
proxy_redirect off;
}
# Well-Known for openid connect
location /.well-known/ {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_pass http://backend:4000/.well-known/;
proxy_redirect off;
}
# Admin Frontend
location /admin {
proxy_http_version 1.1;