@qikdev/sdk 0.1.201 → 0.1.203
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/main.js +2330 -2107
- package/package.json +1 -1
- package/src/api/qik.auth.js +128 -76
- package/src/api/qik.core.js +14 -3
- package/src/api/qik.storage.js +306 -0
- package/src/api/qik.utils.js +5 -2
- package/src/version.js +1 -1
package/package.json
CHANGED
package/src/api/qik.auth.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import axios from 'axios';
|
|
2
2
|
import { EventDispatcher } from './qik.utils.js';
|
|
3
|
+
import { createStorageAdapter } from './qik.storage.js';
|
|
3
4
|
|
|
4
5
|
///////////////////////////////////////////////////
|
|
5
6
|
|
|
@@ -23,19 +24,27 @@ var QikAuth = function(qik) {
|
|
|
23
24
|
|
|
24
25
|
///////////////////////////////////////////////////
|
|
25
26
|
|
|
26
|
-
|
|
27
|
-
|
|
27
|
+
// Create storage adapter based on configuration
|
|
28
|
+
const storageAdapter = createStorageAdapter({
|
|
29
|
+
useHttpOnlyCookies: qik.useHttpOnlyCookies,
|
|
30
|
+
cookieConfig: qik.cookieConfig
|
|
31
|
+
});
|
|
32
|
+
|
|
28
33
|
const tokenBufferSeconds = 10;
|
|
29
34
|
|
|
30
35
|
///////////////////////////////////////////////////
|
|
31
36
|
|
|
32
37
|
const service = {
|
|
33
38
|
debug: false,
|
|
39
|
+
storageAdapter: storageAdapter,
|
|
34
40
|
}
|
|
35
41
|
|
|
42
|
+
// Backwards compatibility - keep store reference
|
|
36
43
|
Object.defineProperty(service, 'store', {
|
|
37
|
-
|
|
38
|
-
|
|
44
|
+
get: function() {
|
|
45
|
+
return { user: storageAdapter.getUser() };
|
|
46
|
+
},
|
|
47
|
+
enumerable: true
|
|
39
48
|
});
|
|
40
49
|
|
|
41
50
|
//Create a new dispatcher
|
|
@@ -47,7 +56,7 @@ var QikAuth = function(qik) {
|
|
|
47
56
|
function dispatch(parameters) {
|
|
48
57
|
|
|
49
58
|
//Get the current user
|
|
50
|
-
var user =
|
|
59
|
+
var user = storageAdapter.getUser();
|
|
51
60
|
|
|
52
61
|
//Dispatch the change to the listeners
|
|
53
62
|
if (service.onChange) {
|
|
@@ -75,8 +84,9 @@ var QikAuth = function(qik) {
|
|
|
75
84
|
|
|
76
85
|
service.set = function(user, parameters, stopDispatch) {
|
|
77
86
|
|
|
78
|
-
|
|
79
|
-
|
|
87
|
+
const currentUser = storageAdapter.getUser();
|
|
88
|
+
if (JSON.stringify(currentUser) != JSON.stringify(user)) {
|
|
89
|
+
storageAdapter.setUser(user);
|
|
80
90
|
if (!stopDispatch) {
|
|
81
91
|
return dispatch(parameters)
|
|
82
92
|
}
|
|
@@ -95,7 +105,7 @@ var QikAuth = function(qik) {
|
|
|
95
105
|
*/
|
|
96
106
|
|
|
97
107
|
service.logout = function() {
|
|
98
|
-
|
|
108
|
+
storageAdapter.clearUser();
|
|
99
109
|
qik.cache.reset();
|
|
100
110
|
return dispatch()
|
|
101
111
|
}
|
|
@@ -288,6 +298,15 @@ var QikAuth = function(qik) {
|
|
|
288
298
|
bypassInterceptor: true
|
|
289
299
|
}
|
|
290
300
|
|
|
301
|
+
// Check if we're in cookie mode
|
|
302
|
+
const isCookieMode = storageAdapter.isCookieMode && storageAdapter.isCookieMode();
|
|
303
|
+
|
|
304
|
+
if (isCookieMode) {
|
|
305
|
+
// Signal to backend that we want cookie-based auth
|
|
306
|
+
credentials.useCookies = true;
|
|
307
|
+
postOptions.withCredentials = true;
|
|
308
|
+
}
|
|
309
|
+
|
|
291
310
|
/////////////////////////////////////////////
|
|
292
311
|
|
|
293
312
|
var url = `${qik.apiURL}/user/login`;
|
|
@@ -305,7 +324,6 @@ var QikAuth = function(qik) {
|
|
|
305
324
|
|
|
306
325
|
if (autoAuthenticate) {
|
|
307
326
|
service.set(res.data);
|
|
308
|
-
|
|
309
327
|
}
|
|
310
328
|
|
|
311
329
|
resolve(res);
|
|
@@ -391,6 +409,15 @@ var QikAuth = function(qik) {
|
|
|
391
409
|
bypassInterceptor: true
|
|
392
410
|
}
|
|
393
411
|
|
|
412
|
+
// Check if we're in cookie mode
|
|
413
|
+
const isCookieMode = storageAdapter.isCookieMode && storageAdapter.isCookieMode();
|
|
414
|
+
|
|
415
|
+
if (isCookieMode) {
|
|
416
|
+
// Signal to backend that we want cookie-based auth
|
|
417
|
+
credentials.useCookies = true;
|
|
418
|
+
postOptions.withCredentials = true;
|
|
419
|
+
}
|
|
420
|
+
|
|
394
421
|
/////////////////////////////////////////////
|
|
395
422
|
|
|
396
423
|
var url = `${qik.apiURL}/user/signup`;
|
|
@@ -581,18 +608,29 @@ var QikAuth = function(qik) {
|
|
|
581
608
|
|
|
582
609
|
var currentUser = service.getCurrentUser();
|
|
583
610
|
if (!currentUser) {
|
|
584
|
-
|
|
585
611
|
return Promise.reject('No user');
|
|
586
612
|
}
|
|
587
613
|
|
|
614
|
+
// Check if we're in cookie mode
|
|
615
|
+
const isCookieMode = storageAdapter.isCookieMode && storageAdapter.isCookieMode();
|
|
616
|
+
|
|
617
|
+
if (isCookieMode) {
|
|
618
|
+
// In cookie mode, we can't check token expiry from JavaScript
|
|
619
|
+
// Just attempt a refresh if forced, otherwise let the server handle it
|
|
620
|
+
if (forceRefresh) {
|
|
621
|
+
return await service.refreshAccessToken();
|
|
622
|
+
} else {
|
|
623
|
+
// Return a placeholder - server will handle token validation
|
|
624
|
+
return 'cookie_mode_token';
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
// localStorage mode - existing token validation logic
|
|
588
629
|
var { token } = currentUser;
|
|
589
630
|
if (!token) {
|
|
590
|
-
|
|
591
631
|
return Promise.reject('No token');
|
|
592
632
|
}
|
|
593
633
|
|
|
594
|
-
/////////////////////////////////////////////////////
|
|
595
|
-
|
|
596
634
|
//Check our date
|
|
597
635
|
var now = new Date();
|
|
598
636
|
|
|
@@ -600,25 +638,18 @@ var QikAuth = function(qik) {
|
|
|
600
638
|
//retiring the token
|
|
601
639
|
now.setSeconds(now.getSeconds() + tokenBufferSeconds);
|
|
602
640
|
|
|
603
|
-
/////////////////////////////////////////////////////
|
|
604
|
-
|
|
605
641
|
var expires = new Date(token.expires);
|
|
606
642
|
|
|
607
643
|
if (forceRefresh) {
|
|
608
|
-
console.log('force refresh valid token', token.refreshToken)
|
|
609
644
|
return await service.refreshAccessToken(token.refreshToken);
|
|
610
645
|
}
|
|
611
646
|
|
|
612
647
|
//If the token is still fresh
|
|
613
648
|
if (now < expires) {
|
|
614
|
-
|
|
615
649
|
return token;
|
|
616
650
|
} else {
|
|
617
|
-
|
|
618
651
|
return await service.refreshAccessToken(token.refreshToken);
|
|
619
652
|
}
|
|
620
|
-
|
|
621
|
-
|
|
622
653
|
}
|
|
623
654
|
|
|
624
655
|
///////////////////////////////////////////////////
|
|
@@ -627,78 +658,77 @@ var QikAuth = function(qik) {
|
|
|
627
658
|
|
|
628
659
|
service.refreshAccessToken = async function(refreshToken) {
|
|
629
660
|
|
|
630
|
-
// /////////////////////////////////////////////
|
|
631
|
-
|
|
632
|
-
// if (appContext) {
|
|
633
|
-
|
|
634
|
-
// } else {
|
|
635
|
-
|
|
636
|
-
// }
|
|
637
|
-
|
|
638
|
-
// /////////////////////////////////////////////
|
|
639
|
-
|
|
640
661
|
//If there is already a request in progress
|
|
641
662
|
if (refreshContext.inflightRefreshRequest) {
|
|
642
|
-
|
|
643
663
|
return refreshContext.inflightRefreshRequest;
|
|
644
664
|
}
|
|
645
665
|
|
|
646
666
|
/////////////////////////////////////////////////////
|
|
647
667
|
|
|
648
|
-
//
|
|
668
|
+
// Check if we're in cookie mode
|
|
669
|
+
const isCookieMode = storageAdapter.isCookieMode && storageAdapter.isCookieMode();
|
|
649
670
|
|
|
671
|
+
//Create a refresh request
|
|
650
672
|
refreshContext.inflightRefreshRequest = new Promise(function(resolve, reject) {
|
|
651
673
|
|
|
652
|
-
|
|
653
|
-
|
|
674
|
+
let requestBody = {};
|
|
675
|
+
let requestOptions = {
|
|
676
|
+
bypassInterceptor: true,
|
|
677
|
+
withoutToken: true,
|
|
678
|
+
};
|
|
654
679
|
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
680
|
+
if (isCookieMode) {
|
|
681
|
+
// In cookie mode, refresh token is sent via httpOnly cookie
|
|
682
|
+
// No need to include it in the request body
|
|
683
|
+
requestOptions.withCredentials = true;
|
|
684
|
+
} else {
|
|
685
|
+
// In localStorage mode, send refresh token in request body
|
|
686
|
+
if (!refreshToken) {
|
|
687
|
+
refreshContext.inflightRefreshRequest = null;
|
|
688
|
+
return reject(new Error('No refresh token provided for localStorage mode'));
|
|
689
|
+
}
|
|
690
|
+
requestBody.refreshToken = refreshToken;
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
qik.api.post(`/user/refresh`, requestBody, requestOptions)
|
|
661
694
|
.then(function tokenRefreshComplete(res) {
|
|
662
695
|
|
|
663
696
|
//Update the user with any changes
|
|
664
697
|
//returned back from the refresh request
|
|
665
|
-
if (!res) {
|
|
666
|
-
|
|
698
|
+
if (!res || !res.data) {
|
|
667
699
|
refreshContext.inflightRefreshRequest = null;
|
|
668
|
-
return reject();
|
|
669
|
-
|
|
670
|
-
} else {
|
|
671
|
-
//Update with our new session
|
|
672
|
-
service.set(res.data);
|
|
700
|
+
return reject(new Error('Invalid refresh response'));
|
|
701
|
+
}
|
|
673
702
|
|
|
703
|
+
//Update with our new session
|
|
704
|
+
service.set(res.data);
|
|
705
|
+
dispatch();
|
|
674
706
|
|
|
675
|
-
|
|
707
|
+
// Return appropriate response based on mode
|
|
708
|
+
if (isCookieMode) {
|
|
709
|
+
// In cookie mode, just indicate success - tokens are in cookies
|
|
710
|
+
resolve('cookie_token_refreshed');
|
|
711
|
+
} else {
|
|
712
|
+
// In localStorage mode, return the actual access token
|
|
713
|
+
const newToken = res.data.token?.accessToken;
|
|
714
|
+
if (newToken) {
|
|
715
|
+
resolve(newToken);
|
|
716
|
+
} else {
|
|
717
|
+
reject(new Error('No access token in refresh response'));
|
|
718
|
+
}
|
|
676
719
|
}
|
|
677
720
|
|
|
678
|
-
//Resolve with the new token
|
|
679
|
-
resolve(res.data.token);
|
|
680
|
-
|
|
681
721
|
//Remove the inflight request
|
|
682
722
|
setTimeout(function() {
|
|
683
723
|
refreshContext.inflightRefreshRequest = null;
|
|
684
|
-
})
|
|
685
|
-
|
|
724
|
+
});
|
|
686
725
|
|
|
687
726
|
})
|
|
688
727
|
.catch(function(err) {
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
//TODO Check if invalid_refresh_token
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
728
|
setTimeout(function() {
|
|
696
729
|
refreshContext.inflightRefreshRequest = null;
|
|
697
730
|
});
|
|
698
731
|
reject(err);
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
732
|
});
|
|
703
733
|
});
|
|
704
734
|
|
|
@@ -723,18 +753,26 @@ var QikAuth = function(qik) {
|
|
|
723
753
|
return qik.api.get('/user')
|
|
724
754
|
.then(function(res) {
|
|
725
755
|
|
|
726
|
-
|
|
727
756
|
if (res.data) {
|
|
728
|
-
|
|
729
|
-
|
|
757
|
+
const currentUser = storageAdapter.getUser();
|
|
758
|
+
if (currentUser) {
|
|
759
|
+
// Update the session data within the current user object
|
|
760
|
+
const updatedUser = { ...currentUser };
|
|
761
|
+
if (updatedUser.session) {
|
|
762
|
+
Object.assign(updatedUser.session, res.data);
|
|
763
|
+
} else {
|
|
764
|
+
updatedUser.session = res.data;
|
|
765
|
+
}
|
|
766
|
+
service.set(updatedUser);
|
|
767
|
+
} else {
|
|
768
|
+
// No current user, set the response data as new user
|
|
769
|
+
service.set(res.data);
|
|
730
770
|
}
|
|
731
771
|
} else {
|
|
732
772
|
service.set(null);
|
|
733
773
|
}
|
|
734
774
|
|
|
735
|
-
|
|
736
775
|
retryCount = 0;
|
|
737
|
-
|
|
738
776
|
dispatch();
|
|
739
777
|
})
|
|
740
778
|
.catch(function(err) {
|
|
@@ -749,7 +787,6 @@ var QikAuth = function(qik) {
|
|
|
749
787
|
// service.sync();
|
|
750
788
|
// }
|
|
751
789
|
|
|
752
|
-
|
|
753
790
|
});
|
|
754
791
|
}
|
|
755
792
|
|
|
@@ -763,7 +800,7 @@ var QikAuth = function(qik) {
|
|
|
763
800
|
* const me = sdk.auth.getCurrentUser();
|
|
764
801
|
*/
|
|
765
802
|
service.getCurrentUser = function() {
|
|
766
|
-
return
|
|
803
|
+
return storageAdapter.getUser();
|
|
767
804
|
}
|
|
768
805
|
|
|
769
806
|
|
|
@@ -777,7 +814,13 @@ var QikAuth = function(qik) {
|
|
|
777
814
|
*/
|
|
778
815
|
service.getCurrentToken = function() {
|
|
779
816
|
|
|
817
|
+
// First try to get token from storage adapter
|
|
818
|
+
var accessToken = storageAdapter.getAccessToken();
|
|
819
|
+
if (accessToken) {
|
|
820
|
+
return accessToken;
|
|
821
|
+
}
|
|
780
822
|
|
|
823
|
+
// For localStorage mode, check user object for token
|
|
781
824
|
var user = service.getCurrentUser();
|
|
782
825
|
|
|
783
826
|
//User is not logged in
|
|
@@ -819,7 +862,21 @@ var QikAuth = function(qik) {
|
|
|
819
862
|
|
|
820
863
|
//////////////////////////////
|
|
821
864
|
|
|
822
|
-
|
|
865
|
+
// Check if we're in cookie mode
|
|
866
|
+
const isCookieMode = storageAdapter.isCookieMode && storageAdapter.isCookieMode();
|
|
867
|
+
|
|
868
|
+
if (isCookieMode) {
|
|
869
|
+
// In cookie mode, browser automatically includes httpOnly cookies
|
|
870
|
+
// We don't need to manually add Authorization headers or handle token refresh
|
|
871
|
+
// Just ensure withCredentials is set for cross-origin requests
|
|
872
|
+
if (!originalRequest.withCredentials) {
|
|
873
|
+
originalRequest.withCredentials = true;
|
|
874
|
+
}
|
|
875
|
+
return originalRequest;
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
// localStorage mode - existing logic for manual token management
|
|
879
|
+
var userDetails = service.getCurrentUser();
|
|
823
880
|
var accessToken;
|
|
824
881
|
var refreshToken;
|
|
825
882
|
var expiryDate;
|
|
@@ -839,11 +896,8 @@ var QikAuth = function(qik) {
|
|
|
839
896
|
if (accessToken) {
|
|
840
897
|
//Set the token of the request as the user's access token
|
|
841
898
|
originalRequest.headers['Authorization'] = `Bearer ${accessToken}`;
|
|
842
|
-
|
|
843
|
-
|
|
844
899
|
} else {
|
|
845
900
|
//Return the original request without a token
|
|
846
|
-
|
|
847
901
|
return originalRequest;
|
|
848
902
|
}
|
|
849
903
|
|
|
@@ -851,8 +905,6 @@ var QikAuth = function(qik) {
|
|
|
851
905
|
|
|
852
906
|
//If no refresh token
|
|
853
907
|
if (!refreshToken) {
|
|
854
|
-
|
|
855
|
-
|
|
856
908
|
//Continue with the original request
|
|
857
909
|
return originalRequest;
|
|
858
910
|
}
|
|
@@ -935,4 +987,4 @@ var QikAuth = function(qik) {
|
|
|
935
987
|
}
|
|
936
988
|
|
|
937
989
|
|
|
938
|
-
export default QikAuth;
|
|
990
|
+
export default QikAuth;
|
package/src/api/qik.core.js
CHANGED
|
@@ -21,15 +21,26 @@ import { EventDispatcher } from './qik.utils.js';
|
|
|
21
21
|
* @constructor
|
|
22
22
|
* @param {Object} options
|
|
23
23
|
* @param {String} options.apiURL The remote URL of the Qik API you want to connect to. Options are 'staging', 'production' or you may set a specific URL eg. 'https://api.qik.io' (do not include trailing slash). If no value is provided, will default to 'production'.
|
|
24
|
-
* @param {String} options.applicationToken When running as a static application, (for example a website) you may set the application's access token before you initialize the Qik instance here.
|
|
24
|
+
* @param {String} options.applicationToken When running as a static application, (for example a website) you may set the application's access token before you initialize the Qik instance here.
|
|
25
|
+
* @param {Boolean} options.useHttpOnlyCookies When set to true, authentication tokens will be stored in secure httpOnly cookies instead of localStorage. This provides enhanced security against XSS attacks. Requires backend support for cookie-based authentication.
|
|
26
|
+
* @param {Object} options.cookieConfig Configuration options for cookie storage when useHttpOnlyCookies is true.
|
|
27
|
+
* @param {String} options.cookieConfig.domain Cookie domain (auto-detected if not specified).
|
|
28
|
+
* @param {Boolean} options.cookieConfig.secure Whether cookies should only be sent over HTTPS (default: true).
|
|
29
|
+
* @param {String} options.cookieConfig.sameSite SameSite cookie attribute ('strict', 'lax', or 'none', default: 'lax').
|
|
25
30
|
* @example
|
|
26
31
|
*
|
|
27
32
|
* //Import the Qik package
|
|
28
33
|
* import Qik from '@qikdev/sdk';
|
|
29
34
|
*
|
|
30
|
-
* //Create a new Qik instance
|
|
35
|
+
* //Create a new Qik instance with localStorage (default)
|
|
31
36
|
* var qik = new Qik();
|
|
32
37
|
*
|
|
38
|
+
* //Create a new Qik instance with httpOnly cookies
|
|
39
|
+
* var qik = new Qik({
|
|
40
|
+
* apiURL: 'production',
|
|
41
|
+
* useHttpOnlyCookies: true
|
|
42
|
+
* });
|
|
43
|
+
*
|
|
33
44
|
* //Request the current user session endpoint from the Qik API
|
|
34
45
|
* qik.api.get('/session').then(function(res) {
|
|
35
46
|
* console.log('User session is ', res.data);
|
|
@@ -243,4 +254,4 @@ export default function(options) {
|
|
|
243
254
|
|
|
244
255
|
return core;
|
|
245
256
|
|
|
246
|
-
}
|
|
257
|
+
}
|