diff --git a/app/api/auth/[...nextauth]/route.ts b/app/api/auth/[...nextauth]/route.ts index b2c0d4f1..d48e37b5 100644 --- a/app/api/auth/[...nextauth]/route.ts +++ b/app/api/auth/[...nextauth]/route.ts @@ -97,26 +97,73 @@ export const authOptions: NextAuthOptions = { // Get Rocket.Chat token for the user using their Keycloak password try { - const rocketChatResponse = await fetch('https://parole.slm-lab.net/api/v1/login', { - method: 'POST', + // Get user's personal access tokens using admin credentials + const tokensResponse = await fetch('https://parole.slm-lab.net/api/v1/users.getPersonalAccessTokens', { headers: { + 'X-Auth-Token': process.env.ROCKET_CHAT_TOKEN!, + 'X-User-Id': process.env.ROCKET_CHAT_USER_ID!, 'Content-Type': 'application/json', }, body: JSON.stringify({ - user: token.username, - password: account.access_token, // Use the Keycloak access token as password + username: token.username, }), }); - if (rocketChatResponse.ok) { - const rocketChatData = await rocketChatResponse.json() as RocketChatLoginResponse; - if (rocketChatData.data) { - token.rocketChatToken = rocketChatData.data.authToken; - token.rocketChatUserId = rocketChatData.data.userId; + if (!tokensResponse.ok) { + console.error('Failed to get personal access tokens:', await tokensResponse.text()); + return token; + } + + const tokensData = await tokensResponse.json(); + console.log('Personal access tokens response:', tokensData); + + // Find or create a token for this user + const tokenName = `keycloak-${token.username}`; + let personalToken: string | null = null; + let rocketChatUserId: string | null = null; + + if (tokensData.tokens && tokensData.tokens.length > 0) { + // Use existing token + const existingToken = tokensData.tokens.find((t: any) => t.name === tokenName); + if (existingToken) { + personalToken = existingToken.lastTokenPart; + rocketChatUserId = tokensData.userId; } } + + if (!personalToken) { + // Create new token + const createTokenResponse = await fetch('https://parole.slm-lab.net/api/v1/users.generatePersonalAccessToken', { + method: 'POST', + headers: { + 'X-Auth-Token': process.env.ROCKET_CHAT_TOKEN!, + 'X-User-Id': process.env.ROCKET_CHAT_USER_ID!, + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + username: token.username, + tokenName, + bypassTwoFactor: true, + }), + }); + + if (createTokenResponse.ok) { + const createTokenData = await createTokenResponse.json(); + personalToken = createTokenData.token; + rocketChatUserId = createTokenData.userId; + } else { + console.error('Failed to create personal access token:', await createTokenResponse.text()); + return token; + } + } + + if (personalToken && rocketChatUserId) { + token.rocketChatToken = personalToken; + token.rocketChatUserId = rocketChatUserId; + } + } catch (error) { - console.error('Error getting Rocket.Chat token:', error); + console.error('Error in Rocket.Chat authentication:', error); } return token; @@ -139,7 +186,7 @@ export const authOptions: NextAuthOptions = { grant_type: "refresh_token", client_id: process.env.KEYCLOAK_CLIENT_ID!, client_secret: process.env.KEYCLOAK_CLIENT_SECRET!, - refresh_token: token.refreshToken as string, + refresh_token: token.refreshToken, }), } ); @@ -207,3 +254,4 @@ export const authOptions: NextAuthOptions = { const handler = NextAuth(authOptions); export { handler as GET, handler as POST }; + diff --git a/types/next-auth.d.ts b/types/next-auth.d.ts index a6d95d9b..4afa3482 100644 --- a/types/next-auth.d.ts +++ b/types/next-auth.d.ts @@ -46,3 +46,18 @@ declare module "next-auth" { realm_roles: string[]; } } + +declare module "next-auth/jwt" { + interface JWT { + accessToken: string; + refreshToken: string; + accessTokenExpires: number; + first_name: string; + last_name: string; + username: string; + role: string[]; + rocketChatToken: string; + rocketChatUserId: string; + error?: string; + } +}