1
1
import { Logger } from '@nestjs/common' ;
2
2
import AdminClient from 'keycloak-admin' ;
3
- import { Client , GrantBody , Issuer , TokenSet } from 'openid-client' ;
3
+ import { Client , Issuer , TokenSet } from 'openid-client' ;
4
4
import { KeycloakAdminOptions } from './interfaces' ;
5
+ import { ResourceManager } from './lib/resource-manager' ;
5
6
6
7
export class KeycloakAdminService {
7
8
private logger = new Logger ( KeycloakAdminService . name ) ;
8
9
9
- private options : KeycloakAdminOptions ;
10
- private client : AdminClient ;
11
- private tokenSet : TokenSet | null | undefined ;
12
- private issuerClient : Client | null | undefined ;
13
- private connectionConfig : GrantBody & any ;
10
+ public readonly options : KeycloakAdminOptions ;
11
+ private tokenSet ?: TokenSet ;
12
+ private issuerClient ?: Client ;
13
+ public resourceManager : ResourceManager ;
14
+ public client : AdminClient ;
14
15
15
16
constructor ( options : KeycloakAdminOptions ) {
16
17
this . options = options ;
17
18
this . client = new AdminClient ( options . config ) ;
19
+ this . resourceManager = new ResourceManager ( this ) ;
18
20
this . initConnection ( ) ;
19
21
}
20
22
@@ -27,9 +29,6 @@ export class KeycloakAdminService {
27
29
grantType : 'client_credentials' ,
28
30
} as any ) ;
29
31
30
- if ( ! this . options . config . baseUrl ) {
31
- throw new Error ( `Base url is missing from options.` ) ;
32
- }
33
32
const keycloakIssuer = await Issuer . discover ( this . options . config . jwtIssuer ) ;
34
33
35
34
this . issuerClient = new keycloakIssuer . Client ( {
@@ -46,46 +45,20 @@ export class KeycloakAdminService {
46
45
this . logger . log (
47
46
`Initial token expires at ${ new Date ( this . tokenSet . expires_at ! ) } ` ,
48
47
) ;
49
-
50
- this . initRefresh ( ) ;
51
48
}
52
49
53
- async initRefresh ( ) {
54
- // Periodically using refresh_token grant flow to get new access token here
55
- // TODO: it will be better to check for token expiration instead of interval check
56
- setInterval ( async ( ) => {
57
- const tokenSet = this . tokenSet ;
58
-
59
- if ( ! tokenSet || ! tokenSet ?. refresh_token ) {
60
- return this . logger . warn (
61
- 'Refresh token is missing. Refresh doesnt work.' ,
62
- ) ;
63
- }
50
+ async refreshGrant ( ) : Promise < TokenSet > {
51
+ if ( this . tokenSet && ! this . tokenSet . expired ( ) ) {
52
+ return this . tokenSet ;
53
+ }
64
54
65
- if ( ! tokenSet . expired ( ) ) {
66
- return this . logger . verbose ( `Omitting refreshing of Keycloak token.` ) ;
67
- }
55
+ this . logger . verbose ( `Grant token expired, refreshing.` ) ;
68
56
69
- try {
70
- this . tokenSet = await this . issuerClient ?. refresh (
71
- tokenSet . refresh_token ,
72
- ) ;
73
- this . logger . log ( 'Successfully refreshed token' ) ;
74
- } catch ( e ) {
75
- if ( e . name === 'TimeoutError' || e ?. error === 'invalid_grant' ) {
76
- this . tokenSet = await this . issuerClient ?. grant ( this . connectionConfig ) ;
77
- } else {
78
- this . logger . error ( e ) ;
79
- throw e ;
80
- }
81
- }
82
- if ( this . tokenSet ?. access_token ) {
83
- this . client . setAccessToken ( this . tokenSet . access_token ) ;
84
- }
85
- } , 58 * 1000 ) ; // 58 seconds
86
- }
57
+ this . tokenSet = await this . issuerClient ?. refresh (
58
+ this . tokenSet ! . refresh_token ! ,
59
+ ) ;
87
60
88
- getClient ( ) {
89
- return this . client ;
61
+ this . client . setAccessToken ( this . tokenSet ! . access_token ! ) ;
62
+ return this . tokenSet ! ;
90
63
}
91
64
}
0 commit comments