@@ -6,7 +6,7 @@ import { Cipher } from 'n8n-core';
6
6
import { Logger } from 'n8n-core' ;
7
7
import nock from 'nock' ;
8
8
9
- import { Time } from '@/constants' ;
9
+ import { CREDENTIAL_BLANKING_VALUE , Time } from '@/constants' ;
10
10
import { OAuth2CredentialController } from '@/controllers/oauth/oauth2-credential.controller' ;
11
11
import { CredentialsHelper } from '@/credentials-helper' ;
12
12
import type { CredentialsEntity } from '@/databases/entities/credentials-entity' ;
@@ -257,5 +257,85 @@ describe('OAuth2CredentialController', () => {
257
257
) ;
258
258
expect ( res . render ) . toHaveBeenCalledWith ( 'oauth-callback' ) ;
259
259
} ) ;
260
+
261
+ it ( 'merges oauthTokenData if it already exists' , async ( ) => {
262
+ credentialsRepository . findOneBy . mockResolvedValueOnce ( credential ) ;
263
+ credentialsHelper . getDecrypted . mockResolvedValueOnce ( {
264
+ csrfSecret,
265
+ oauthTokenData : { token : true } ,
266
+ } ) ;
267
+ jest . spyOn ( Csrf . prototype , 'verify' ) . mockReturnValueOnce ( true ) ;
268
+ nock ( 'https://example.domain' )
269
+ . post (
270
+ '/token' ,
271
+ 'code=code&grant_type=authorization_code&redirect_uri=http%3A%2F%2Flocalhost%3A5678%2Frest%2Foauth2-credential%2Fcallback' ,
272
+ )
273
+ . reply ( 200 , { access_token : 'access-token' , refresh_token : 'refresh-token' } ) ;
274
+ cipher . encrypt . mockReturnValue ( 'encrypted' ) ;
275
+
276
+ await controller . handleCallback ( req , res ) ;
277
+
278
+ expect ( externalHooks . run ) . toHaveBeenCalledWith ( 'oauth2.callback' , [
279
+ expect . objectContaining ( {
280
+ clientId : 'test-client-id' ,
281
+ redirectUri : 'http://localhost:5678/rest/oauth2-credential/callback' ,
282
+ } ) ,
283
+ ] ) ;
284
+ expect ( cipher . encrypt ) . toHaveBeenCalledWith ( {
285
+ oauthTokenData : {
286
+ token : true ,
287
+ access_token : 'access-token' ,
288
+ refresh_token : 'refresh-token' ,
289
+ } ,
290
+ } ) ;
291
+ expect ( credentialsRepository . update ) . toHaveBeenCalledWith (
292
+ '1' ,
293
+ expect . objectContaining ( {
294
+ data : 'encrypted' ,
295
+ id : '1' ,
296
+ name : 'Test Credential' ,
297
+ type : 'oAuth2Api' ,
298
+ } ) ,
299
+ ) ;
300
+ expect ( res . render ) . toHaveBeenCalledWith ( 'oauth-callback' ) ;
301
+ } ) ;
302
+
303
+ it ( 'overwrites oauthTokenData if it is a string' , async ( ) => {
304
+ credentialsRepository . findOneBy . mockResolvedValueOnce ( credential ) ;
305
+ credentialsHelper . getDecrypted . mockResolvedValueOnce ( {
306
+ csrfSecret,
307
+ oauthTokenData : CREDENTIAL_BLANKING_VALUE ,
308
+ } ) ;
309
+ jest . spyOn ( Csrf . prototype , 'verify' ) . mockReturnValueOnce ( true ) ;
310
+ nock ( 'https://example.domain' )
311
+ . post (
312
+ '/token' ,
313
+ 'code=code&grant_type=authorization_code&redirect_uri=http%3A%2F%2Flocalhost%3A5678%2Frest%2Foauth2-credential%2Fcallback' ,
314
+ )
315
+ . reply ( 200 , { access_token : 'access-token' , refresh_token : 'refresh-token' } ) ;
316
+ cipher . encrypt . mockReturnValue ( 'encrypted' ) ;
317
+
318
+ await controller . handleCallback ( req , res ) ;
319
+
320
+ expect ( externalHooks . run ) . toHaveBeenCalledWith ( 'oauth2.callback' , [
321
+ expect . objectContaining ( {
322
+ clientId : 'test-client-id' ,
323
+ redirectUri : 'http://localhost:5678/rest/oauth2-credential/callback' ,
324
+ } ) ,
325
+ ] ) ;
326
+ expect ( cipher . encrypt ) . toHaveBeenCalledWith ( {
327
+ oauthTokenData : { access_token : 'access-token' , refresh_token : 'refresh-token' } ,
328
+ } ) ;
329
+ expect ( credentialsRepository . update ) . toHaveBeenCalledWith (
330
+ '1' ,
331
+ expect . objectContaining ( {
332
+ data : 'encrypted' ,
333
+ id : '1' ,
334
+ name : 'Test Credential' ,
335
+ type : 'oAuth2Api' ,
336
+ } ) ,
337
+ ) ;
338
+ expect ( res . render ) . toHaveBeenCalledWith ( 'oauth-callback' ) ;
339
+ } ) ;
260
340
} ) ;
261
341
} ) ;
0 commit comments