@@ -9,22 +9,23 @@ import { JWT } from 'next-auth/jwt';
9
9
import KeycloakProvider , { KeycloakProfile } from 'next-auth/providers/keycloak' ;
10
10
import { IS_PROD , AUTH_SERVER_URL , AUTH_RELM , AUTH_RESOURCE , AUTH_SECRET , USER_TOKEN_REFRESH_INTERVAL } from '@/config' ;
11
11
import { TEAM_SA_PREFIX , GlobalRole , RoleToSessionProp , sessionRolePropKeys } from '@/constants' ;
12
+ import { logger } from '@/core/logging' ;
12
13
import prisma from '@/core/prisma' ;
13
14
import { EventType , Organization , TaskStatus , UserSession } from '@/prisma/client' ;
14
15
import { createEvent } from '@/services/db' ;
15
16
import { upsertUser } from '@/services/db/user' ;
16
-
17
17
interface DecodedToken {
18
18
resource_access ?: Record < string , { roles : string [ ] } > ;
19
+ idir_guid ?: string | null ;
19
20
email : string ;
20
21
sub : string ;
21
22
}
22
-
23
+ type KeycloakProfileWithIdir = KeycloakProfile & { idir_guid ?: string } ;
23
24
async function updateUserSession ( tokens ?: { access_token ?: string ; refresh_token ?: string ; id_token ?: string } ) {
24
25
const { access_token = '' , refresh_token = '' , id_token = '' } = tokens ?? { } ;
25
- const decodedToken = jwt . decode ( access_token ) as DecodedToken ;
26
- const { resource_access = { } , sub = '' , email = '' } = decodedToken || { } ;
27
26
27
+ const decodedToken = jwt . decode ( access_token ) as DecodedToken ;
28
+ const { resource_access = { } , sub = '' , email = '' , idir_guid } = decodedToken || { } ;
28
29
const roles = _get ( resource_access , `${ AUTH_RESOURCE } .roles` , [ ] ) as string [ ] ;
29
30
const teams : SessionTokenTeams [ ] = [ ] ;
30
31
@@ -39,6 +40,7 @@ async function updateUserSession(tokens?: { access_token?: string; refresh_token
39
40
40
41
const userSessionData = {
41
42
email : loweremail ,
43
+ idirGuid : idir_guid ,
42
44
nextTokenRefreshTime,
43
45
roles,
44
46
sub,
@@ -148,6 +150,7 @@ export async function generateSession({
148
150
name : '' ,
149
151
email : '' ,
150
152
image : '' ,
153
+ idirGuid : '' ,
151
154
} ;
152
155
153
156
session . tasks = [ ] ;
@@ -156,15 +159,15 @@ export async function generateSession({
156
159
const [ user , userSession ] = await Promise . all ( [
157
160
prisma . user . findFirst ( {
158
161
where : { email : token . email } ,
159
- select : { id : true , email : true , image : true } ,
162
+ select : { id : true , email : true , image : true , idirGuid : true } ,
160
163
} ) ,
161
164
userSessionOverride ??
162
165
prisma . userSession . findFirst ( {
163
166
where : { email : token . email } ,
164
167
} ) ,
165
168
] ) ;
166
-
167
169
if ( userSession ) {
170
+ session . user . idirGuid = userSession . idirGuid ;
168
171
session . idToken = userSession . idToken ;
169
172
session . kcUserId = userSession . sub ;
170
173
session . roles = userSession . roles ;
@@ -179,7 +182,7 @@ export async function generateSession({
179
182
session . user . id = user . id ;
180
183
session . user . email = user . email ;
181
184
session . user . image = user . image ;
182
-
185
+ session . user . idirGuid = user ?. idirGuid ?? token ?. idirGuid ?? session . user . idirGuid ;
183
186
session . userId = user . id ;
184
187
session . userEmail = user . email ;
185
188
session . roles . push ( GlobalRole . User ) ;
@@ -397,8 +400,14 @@ export const authOptions: AuthOptions = {
397
400
secret : AUTH_SECRET ,
398
401
callbacks : {
399
402
async signIn ( { user, account, profile } ) {
400
- const { given_name, family_name, email } = profile as KeycloakProfile ;
403
+ const { given_name, family_name, email, idir_guid } = profile as KeycloakProfileWithIdir ;
404
+
405
+ if ( ! idir_guid ) {
406
+ logger . warn ( `Login blocked: Missing idirGuid for user ${ user ?. email } ` ) ;
407
+ return false ;
408
+ }
401
409
const loweremail = email . toLowerCase ( ) ;
410
+
402
411
const lastSeen = new Date ( ) ;
403
412
404
413
const upsertedUser = await upsertUser ( loweremail , { lastSeen } ) ;
@@ -410,14 +419,13 @@ export const authOptions: AuthOptions = {
410
419
email : loweremail ,
411
420
ministry : '' ,
412
421
idir : '' ,
413
- idirGuid : '' ,
422
+ idirGuid : idir_guid ,
414
423
upn : '' ,
415
424
image : '' ,
416
425
officeLocation : '' ,
417
426
jobTitle : '' ,
418
427
lastSeen,
419
428
} ;
420
-
421
429
await prisma . user . upsert ( {
422
430
where : { email : loweremail } ,
423
431
update : data ,
@@ -429,7 +437,8 @@ export const authOptions: AuthOptions = {
429
437
} ,
430
438
async jwt ( { token, account } : { token : JWT ; account : Account | null } ) {
431
439
if ( account ) {
432
- await updateUserSession ( account ) ;
440
+ const updatedSession = await updateUserSession ( account ) ;
441
+ if ( updatedSession . idirGuid ) token . idirGuid = updatedSession . idirGuid ;
433
442
return token ;
434
443
}
435
444
@@ -441,7 +450,8 @@ export const authOptions: AuthOptions = {
441
450
if ( userSessToRefresh ) {
442
451
const newTokens = await getNewTokens ( userSessToRefresh . refreshToken ) ;
443
452
if ( newTokens ) {
444
- await updateUserSession ( newTokens ) ;
453
+ const refreshedSession = await updateUserSession ( newTokens ) ;
454
+ if ( refreshedSession . idirGuid ) token . idirGuid = refreshedSession . idirGuid ;
445
455
} else {
446
456
await endUserSession ( token . email ) ;
447
457
}
@@ -454,7 +464,6 @@ export const authOptions: AuthOptions = {
454
464
events : {
455
465
async signIn ( { user, account } : { user : User ; account : Account | null } ) {
456
466
if ( ! user ?. email ) return ;
457
-
458
467
const loweremail = user . email . toLowerCase ( ) ;
459
468
const loggedInUser = await prisma . user . findUnique ( {
460
469
where : { email : loweremail } ,
0 commit comments