fix: configure Kong JWT auth flow with consumer credentials
- Add kid claim to auth-service JWT for Kong validation - Add Kong consumer with JWT credential (shared secret via env) - Add agent-config route to Kong for /api/v1/agent-config - Kong Dockerfile uses entrypoint script to inject JWT_SECRET at runtime - Fix frontend login path (/auth/login → /api/v1/auth/login) - Extract tenantId from JWT on login and store as current_tenant - Add auth guard in admin layout (redirect to /login if no token) - Pass JWT_SECRET env var to Kong container in docker-compose Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
28131491e2
commit
48e47975ca
|
|
@ -40,6 +40,8 @@ services:
|
|||
build:
|
||||
context: ../../packages/gateway
|
||||
container_name: it0-api-gateway
|
||||
environment:
|
||||
- JWT_SECRET=${JWT_SECRET:-dev-jwt-secret}
|
||||
ports:
|
||||
- "18000:8000"
|
||||
- "18001:8001"
|
||||
|
|
|
|||
|
|
@ -1,9 +1,25 @@
|
|||
'use client';
|
||||
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { Sidebar } from '@/presentation/components/layout/sidebar';
|
||||
import { TopBar } from '@/presentation/components/layout/top-bar';
|
||||
|
||||
export default function AdminLayout({ children }: { children: React.ReactNode }) {
|
||||
const router = useRouter();
|
||||
const [ready, setReady] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const token = localStorage.getItem('access_token');
|
||||
if (!token) {
|
||||
router.replace('/login');
|
||||
} else {
|
||||
setReady(true);
|
||||
}
|
||||
}, [router]);
|
||||
|
||||
if (!ready) return null;
|
||||
|
||||
return (
|
||||
<div className="flex h-screen">
|
||||
<Sidebar />
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ export default function LoginPage() {
|
|||
setError(null);
|
||||
|
||||
try {
|
||||
const data = await apiClient<LoginResponse>('/auth/login', {
|
||||
const data = await apiClient<LoginResponse>('/api/v1/auth/login', {
|
||||
method: 'POST',
|
||||
body: { email, password },
|
||||
});
|
||||
|
|
@ -32,6 +32,14 @@ export default function LoginPage() {
|
|||
localStorage.setItem('refresh_token', data.refreshToken);
|
||||
localStorage.setItem('user', JSON.stringify(data.user));
|
||||
|
||||
// Decode tenantId from JWT and store as current tenant
|
||||
try {
|
||||
const payload = JSON.parse(atob(data.accessToken.split('.')[1]));
|
||||
if (payload.tenantId) {
|
||||
localStorage.setItem('current_tenant', JSON.stringify({ id: payload.tenantId }));
|
||||
}
|
||||
} catch { /* ignore decode errors */ }
|
||||
|
||||
router.push('/dashboard');
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : 'Login failed');
|
||||
|
|
|
|||
|
|
@ -1,9 +1,13 @@
|
|||
FROM kong:3.7
|
||||
|
||||
COPY config/kong.yml /etc/kong/kong.yml
|
||||
COPY config/kong.yml /etc/kong/kong.yml.tpl
|
||||
COPY config/docker-entrypoint.sh /custom-entrypoint.sh
|
||||
RUN chmod +x /custom-entrypoint.sh
|
||||
|
||||
ENV KONG_DATABASE=off
|
||||
ENV KONG_DECLARATIVE_CONFIG=/etc/kong/kong.yml
|
||||
ENV KONG_PROXY_LISTEN=0.0.0.0:8000
|
||||
ENV KONG_ADMIN_LISTEN=0.0.0.0:8001
|
||||
ENV KONG_LOG_LEVEL=info
|
||||
|
||||
ENTRYPOINT ["/custom-entrypoint.sh"]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,4 @@
|
|||
#!/bin/sh
|
||||
# Substitute JWT_SECRET into Kong declarative config at runtime
|
||||
sed "s/\${JWT_SECRET}/${JWT_SECRET:-dev-jwt-secret}/g" /etc/kong/kong.yml.tpl > /etc/kong/kong.yml
|
||||
exec /docker-entrypoint.sh kong docker-start
|
||||
|
|
@ -1,5 +1,12 @@
|
|||
_format_version: "3.0"
|
||||
|
||||
consumers:
|
||||
- username: it0-system
|
||||
jwt_secrets:
|
||||
- key: it0-auth
|
||||
algorithm: HS256
|
||||
secret: "${JWT_SECRET}"
|
||||
|
||||
services:
|
||||
- name: auth-service
|
||||
url: http://auth-service:3001
|
||||
|
|
@ -24,6 +31,14 @@ services:
|
|||
- http
|
||||
- https
|
||||
|
||||
- name: agent-config-service
|
||||
url: http://agent-service:3002
|
||||
routes:
|
||||
- name: agent-config-routes
|
||||
paths:
|
||||
- /api/v1/agent-config
|
||||
strip_path: false
|
||||
|
||||
- name: ops-service
|
||||
url: http://ops-service:3003
|
||||
routes:
|
||||
|
|
|
|||
|
|
@ -153,7 +153,10 @@ export class AuthService {
|
|||
roles: user.roles,
|
||||
};
|
||||
|
||||
const accessToken = this.jwtService.sign(jwtPayload);
|
||||
const accessToken = this.jwtService.sign({
|
||||
...jwtPayload,
|
||||
kid: 'it0-auth',
|
||||
});
|
||||
|
||||
const refreshToken = this.jwtService.sign(
|
||||
{ sub: user.id, type: 'refresh' },
|
||||
|
|
|
|||
Loading…
Reference in New Issue