Remove unused files and code: - Delete test/debug endpoints (test.get.ts, public.get.ts, user.get.ts, debug-config backup) - Remove unused OAuth wrapper (oauth-authentik.ts) - Clean up debug console.log statements - Simplify code comments Fix TypeScript errors: - Add @types/node dependency - Create index.d.ts with User interface extension - Fix UButton color props (red→error, gray→neutral) - Add type assertions in protected.get.ts Update documentation: - Enhance README.md as template documentation - Update SETUP.md with correct API routes (/api/auth/* instead of /auth/*) - Add NUXT_OAUTH_AUTHENTIK_SERVER_URL_INTERNAL documentation - Update endpoint documentation This commit prepares the repository to be used as a template for future Nuxt 4 + Authentik OAuth projects.
83 lines
2.6 KiB
TypeScript
83 lines
2.6 KiB
TypeScript
import { getQuery } from 'h3'
|
|
import { withQuery } from 'ufo'
|
|
|
|
/**
|
|
* OAuth Authentik Login Handler
|
|
* Handles OAuth flow: initial redirect and callback
|
|
*/
|
|
export default defineEventHandler(async (event) => {
|
|
const runtimeConfig = useRuntimeConfig(event)
|
|
const query = getQuery(event)
|
|
|
|
const config = {
|
|
clientId: runtimeConfig.oauth.authentik.clientId,
|
|
clientSecret: runtimeConfig.oauth.authentik.clientSecret,
|
|
serverUrl: runtimeConfig.oauth.authentik.serverUrl,
|
|
serverUrlInternal: runtimeConfig.oauth.authentik.serverUrlInternal || runtimeConfig.oauth.authentik.serverUrl,
|
|
redirectURL: runtimeConfig.oauth.authentik.redirectURL,
|
|
scope: ['openid', 'profile', 'email'],
|
|
}
|
|
|
|
// Handle OAuth callback
|
|
if (query.code) {
|
|
try {
|
|
// Exchange code for tokens (usar URL interna para comunicación servidor-a-servidor)
|
|
const tokenUrl = `${config.serverUrlInternal}/application/o/token/`
|
|
const tokenResponse = await $fetch(tokenUrl, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
},
|
|
body: new URLSearchParams({
|
|
grant_type: 'authorization_code',
|
|
client_id: config.clientId,
|
|
client_secret: config.clientSecret,
|
|
code: query.code as string,
|
|
redirect_uri: config.redirectURL,
|
|
}),
|
|
})
|
|
|
|
const tokens = tokenResponse as any
|
|
|
|
// Get user info (usar URL interna para comunicación servidor-a-servidor)
|
|
const userInfoUrl = `${config.serverUrlInternal}/application/o/userinfo/`
|
|
const user = await $fetch(userInfoUrl, {
|
|
headers: {
|
|
Authorization: `Bearer ${tokens.access_token}`,
|
|
},
|
|
})
|
|
|
|
// Guardar información del usuario en la sesión
|
|
await setUserSession(event, {
|
|
user: {
|
|
id: (user as any).sub,
|
|
email: (user as any).email,
|
|
name: (user as any).name || (user as any).preferred_username,
|
|
username: (user as any).preferred_username,
|
|
picture: (user as any).picture,
|
|
groups: (user as any).groups || []
|
|
},
|
|
loggedInAt: Date.now()
|
|
})
|
|
|
|
return sendRedirect(event, '/')
|
|
} catch (error: any) {
|
|
console.error('Authentik OAuth error:', error)
|
|
return sendRedirect(event, '/?error=auth_failed')
|
|
}
|
|
}
|
|
|
|
// Initial redirect to Authentik
|
|
const authorizationUrl = withQuery(
|
|
`${config.serverUrl}/application/o/authorize/`,
|
|
{
|
|
client_id: config.clientId,
|
|
redirect_uri: config.redirectURL,
|
|
response_type: 'code',
|
|
scope: config.scope.join(' '),
|
|
}
|
|
)
|
|
|
|
return sendRedirect(event, authorizationUrl)
|
|
})
|