@qikdev/sdk 0.1.0

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.
@@ -0,0 +1,980 @@
1
+ import axios from 'axios';
2
+ import _ from 'lodash';
3
+ import { EventDispatcher } from './qik.utils.js';
4
+
5
+ ///////////////////////////////////////////////////
6
+
7
+ /**
8
+ * Creates a new QikAuth instance.
9
+ * This module provides a number of helper functions for authentication, logging in, signing up, generating and refreshing tokens
10
+ * @alias auth
11
+ * @constructor
12
+ * @hideconstructor
13
+ * @param {QikCore} qik A reference to the parent instance of the QikCore module. This module is usually created by a QikCore instance that passes itself in as the first argument.
14
+ */
15
+ var QikAuth = function(qik) {
16
+
17
+ if (!qik.api) {
18
+ throw new Error(`Can't Instantiate QikAuth before QikAPI exists`);
19
+ }
20
+
21
+ //Keep track of any refresh requests
22
+ var inflightRefreshRequest;
23
+
24
+ ///////////////////////////////////////////////////
25
+
26
+ var defaultStore = {};
27
+ var store = defaultStore;
28
+
29
+ ///////////////////////////////////////////////////
30
+ ///////////////////////////////////////////////////
31
+
32
+ var service = {
33
+ debug: false,
34
+ }
35
+
36
+ Object.defineProperty(service, 'store', {
37
+ value: store,
38
+ writable: false,
39
+ });
40
+
41
+
42
+ //Create a new dispatcher
43
+ var dispatcher = new EventDispatcher();
44
+ dispatcher.bootstrap(service);
45
+
46
+ // console.log('New Dispatcher!', dispatcher)
47
+
48
+ ///////////////////////////////////////////////////
49
+ ///////////////////////////////////////////////////
50
+
51
+ function dispatch(parameters) {
52
+
53
+ //Get the current user
54
+ var user = store.user;
55
+
56
+ //Dispatch the change to the listeners
57
+ if (service.onChange) {
58
+ service.onChange(user);
59
+ }
60
+
61
+ //Dispatch the change event
62
+ dispatcher.dispatch('change', user, parameters);
63
+ }
64
+
65
+ ///////////////////////////////////////////////////
66
+
67
+ function log(message) {
68
+ if (service.debug) {
69
+ console.log(message);
70
+ }
71
+ }
72
+
73
+ ///////////////////////////////////////////////////
74
+
75
+ /**
76
+ *
77
+ * Sets the current user data, often from localStorage or after new session data
78
+ * has been generated from the server after signing in
79
+ * @alias auth.set
80
+ * @param {Object} user The user session object
81
+ * @example
82
+ * QikAsset.set({firstName:'Jeff', lastName:'Andrews', ...})
83
+ */
84
+
85
+ service.set = function(user, parameters, ignoreEvent) {
86
+
87
+ store.user = user;
88
+
89
+ log('qik.auth > user set');
90
+ return dispatch(parameters)
91
+ }
92
+
93
+
94
+
95
+ ///////////////////////////////////////////////////
96
+
97
+ /**
98
+ *
99
+ * Deletes the user session object, clears all Qik caches and tokens
100
+ * from memory
101
+ * @alias auth.logout
102
+ * @example
103
+ * qik.auth.logout()
104
+ */
105
+
106
+ service.logout = function() {
107
+ //Unauthenticated
108
+ // delete store.token;
109
+
110
+ delete store.user;
111
+ qik.cache.reset();
112
+ // delete store.refreshToken;
113
+ // delete store.expires;
114
+
115
+
116
+
117
+ log('qik.auth > user logout');
118
+
119
+
120
+ if (qik.withCredentials) {
121
+
122
+ //Logout of the current application
123
+ window.location.href = '/qik/logout';
124
+
125
+
126
+ }
127
+
128
+
129
+ // if(window && window.localStorage) {
130
+ // window.localStorage.removeItem('qik.user');
131
+ // }
132
+
133
+ return dispatch()
134
+
135
+ }
136
+
137
+ ///////////////////////////////////////////////////
138
+
139
+ /**
140
+ *
141
+ * Retrieves a new session object for a Qik global user for a specified organisation
142
+ * This will only work if the user has a persona in that organisation
143
+ * @alias auth.changeOrganisation
144
+ * @param {String} organisationID The _id of the organisation you wish to log in to
145
+ * @param {Object} options
146
+ * @param {Object} options.disableAutoAuthentication By default this function will set the current user session
147
+ * to organisation you are changing in to.
148
+ * If you want to generate the session without affecting your current session you can set disableAutoAuthentication to true
149
+ * @return {Promise} Resolves to the user session object, or rejects with the responding error
150
+ * @example
151
+ * qik.auth.changeOrganisation('5be504eabf33991239599d63').then(function(userSession) {
152
+ * //New user session will be set automatically
153
+ * var newUserSession = qik.auth.getCurrentUser();
154
+ * })
155
+ * qik.auth.changeOrganisation('5be504eabf33991239599d63', {disableAutoAuthentication:true}).then(function(userSession) {
156
+ * //Set the session manually
157
+ * qik.auth.set(userSession)
158
+ * })
159
+ */
160
+
161
+ service.changeOrganisation = function(organisationID, options) {
162
+
163
+ //Ensure we just have the ID
164
+ organisationID = qik.utils.getStringID(organisationID);
165
+
166
+ //////////////////////////
167
+
168
+ if (!options) {
169
+ options = {};
170
+ }
171
+
172
+ //////////////////////////
173
+
174
+ //Change the users current tokens straight away
175
+ var autoAuthenticate = true;
176
+
177
+ if (options.disableAutoAuthentication) {
178
+ autoAuthenticate = false;
179
+ }
180
+
181
+ //////////////////////////
182
+
183
+ var promise = qik.api.post(`/user/switch/${organisationID}`)
184
+
185
+ promise.then(function(res) {
186
+
187
+ if (autoAuthenticate) {
188
+ qik.cache.reset();
189
+ service.set(res.data);
190
+ }
191
+ }, function(err) {});
192
+
193
+
194
+ return promise;
195
+
196
+ }
197
+
198
+
199
+
200
+ ///////////////////////////////////////////////////
201
+
202
+ /**
203
+ *
204
+ * Impersonates a persona and sets the current session to match the specified persona's context
205
+ * @alias auth.impersonate
206
+ * @param {String} personaID The _id of the persona you wish to impersonate
207
+ * @param {Object} options
208
+ * @return {Promise} Resolves to the user session object, or rejects with the responding error
209
+ * @example
210
+ * qik.auth.impersonate('5be504eabf33991239599d63')
211
+ * .then(function(userSession) {
212
+ * //New user session will be set automatically
213
+ * var newUserSession = qik.auth.getCurrentUser();
214
+ * })
215
+ */
216
+
217
+ service.impersonate = function(personaID, options) {
218
+
219
+ //Ensure we just have the ID
220
+ personaID = qik.utils.getStringID(personaID);
221
+
222
+ //////////////////////////
223
+
224
+ if (!options) {
225
+ options = {};
226
+ }
227
+
228
+ //////////////////////////
229
+
230
+ //Change the users current tokens straight away
231
+ var autoAuthenticate = true;
232
+
233
+ if (options.disableAutoAuthentication) {
234
+ autoAuthenticate = false;
235
+ }
236
+
237
+ //////////////////////////
238
+
239
+ var promise = qik.api.post(`/user/impersonate/${personaID}`)
240
+
241
+ promise.then(function(res) {
242
+
243
+ if (autoAuthenticate) {
244
+ qik.cache.reset();
245
+ service.set(res.data);
246
+ }
247
+ }, function(err) {});
248
+
249
+
250
+ return promise;
251
+
252
+ }
253
+
254
+ ///////////////////////////////////////////////////
255
+ /**
256
+ * Logs the user in to Qik and returns a new user session
257
+ * @alias auth.login
258
+ * @param {Object} credentials
259
+ * @param {String} credentials.email The email address of the user to login as
260
+ * @param {String} credentials.password The password for the user
261
+ * @param {Object} options Extra options and configuration for the request
262
+ * @param {Object} options.disableAutoAuthentication Disable automatic authentication, if true, will not set the current user session
263
+ * @return {Promise} Returns a promise that either resolves with the logged in user session, or rejects with the responding error from the server
264
+ */
265
+ service.login = function(credentials, options) {
266
+
267
+ if (!options) {
268
+ options = {};
269
+ }
270
+
271
+ //////////////////////////
272
+
273
+ //Change the users current tokens straight away
274
+ var autoAuthenticate = true;
275
+
276
+ if (options.disableAutoAuthentication) {
277
+ autoAuthenticate = false;
278
+ }
279
+
280
+ //////////////////////////////////////
281
+
282
+ var promise = new Promise(loginCheck)
283
+
284
+ function loginCheck(resolve, reject) {
285
+
286
+ if (!credentials) {
287
+ return reject({
288
+ message: 'Missing credentials!',
289
+ })
290
+ }
291
+
292
+ if (!credentials.email || !credentials.email.length) {
293
+ return reject({
294
+ message: 'Username was not provided',
295
+ })
296
+ }
297
+
298
+ if (!credentials.password || !credentials.password.length) {
299
+ return reject({
300
+ message: 'Password was not provided',
301
+ })
302
+ }
303
+
304
+ /////////////////////////////////////////////
305
+
306
+ var postOptions = {
307
+ bypassInterceptor: true
308
+ }
309
+
310
+ /////////////////////////////////////////////
311
+
312
+ var url = `${qik.apiURL}/user/login`;
313
+
314
+ /////////////////////////////////////////////
315
+
316
+ //If we have a specified url
317
+ if (options.url) {
318
+ url = options.url;
319
+ }
320
+
321
+ /////////////////////////////////////////////
322
+
323
+ qik.api.post(url, credentials, postOptions).then(function(res) {
324
+
325
+ if (autoAuthenticate) {
326
+ store.user = res.data;
327
+ // console.log('Persist user', store.user)
328
+ dispatch();
329
+ // if (service.onChange) {
330
+ // service.onChange(store.user);
331
+ // }
332
+ }
333
+
334
+ resolve(res);
335
+ }, reject);
336
+ }
337
+
338
+ //////////////////////////////////////
339
+
340
+ return promise;
341
+
342
+ }
343
+
344
+ ///////////////////////////////////////////////////
345
+
346
+ /**
347
+ * Signs up a new user to the current application, this will create a new managed user persona
348
+ * and automatically log in as that persona in the current application context. This function will
349
+ * only work when called in context of an application with the 'Application Token' authentication style.
350
+ * It will create a new user persona in the organisation of the application and return a session with all of the application's
351
+ * permissions and application's logged in user permissions
352
+ * @alias auth.signup
353
+ * @param {Object} credentials
354
+ * @param {String} credentials.firstName The first name for the new user persona
355
+ * @param {String} credentials.lastName The last name for the new user persona
356
+ * @param {String} credentials.email The email address for the new persona
357
+ * @param {String} credentials.password The password to set for the new persona
358
+ * @param {String} credentials.confirmPassword A double check to confirm the new password for the persona
359
+ * @param {Object} options Extra options and configuration for the request
360
+ * @return {Promise} Returns a promise that either resolves to the new authenticated session, or rejects with the responding error from the server
361
+ */
362
+ service.signup = function(credentials, options) {
363
+
364
+ if (!options) {
365
+ options = {};
366
+ }
367
+
368
+
369
+ //////////////////////////
370
+
371
+ //Change the users current tokens straight away
372
+ var autoAuthenticate = true;
373
+
374
+ if (options.disableAutoAuthentication) {
375
+ autoAuthenticate = false;
376
+ }
377
+
378
+ //////////////////////////////////////
379
+
380
+ var promise = new Promise(signupCheck)
381
+
382
+ function signupCheck(resolve, reject) {
383
+
384
+ if (!credentials) {
385
+ return reject({
386
+ message: 'No details provided',
387
+ })
388
+ }
389
+
390
+ if (!credentials.firstName || !credentials.firstName.length) {
391
+ return reject({
392
+ message: 'First Name was not provided',
393
+ })
394
+ }
395
+
396
+ if (!credentials.lastName || !credentials.lastName.length) {
397
+ return reject({
398
+ message: 'Last Name was not provided',
399
+ })
400
+ }
401
+
402
+ if (!credentials.email || !credentials.email.length) {
403
+ return reject({
404
+ message: 'Email/Username was not provided',
405
+ })
406
+ }
407
+
408
+
409
+ if (!credentials.password || !credentials.password.length) {
410
+ return reject({
411
+ message: 'Password was not provided',
412
+ })
413
+ }
414
+
415
+ if (!credentials.confirmPassword || !credentials.confirmPassword.length) {
416
+ return reject({
417
+ message: 'Confirm Password was not provided',
418
+ })
419
+ }
420
+
421
+ if (credentials.confirmPassword != credentials.password) {
422
+ return reject({
423
+ message: 'Your passwords do not match',
424
+ })
425
+ }
426
+
427
+ /////////////////////////////////////////////
428
+
429
+ var postOptions = {
430
+ bypassInterceptor: true
431
+ }
432
+
433
+ /////////////////////////////////////////////
434
+
435
+ var url = `${qik.apiURL}/user/signup`;
436
+
437
+ /////////////////////////////////////////////
438
+
439
+ //If we are authenticating as an application
440
+ if (options.application) {
441
+
442
+ //The url is relative to the domain
443
+ url = `${qik.domain || ''}/qik/application/signup`;
444
+ }
445
+
446
+ //If we have a specified url
447
+ if (options.url) {
448
+ url = options.url;
449
+ }
450
+
451
+ /////////////////////////////////////////////
452
+
453
+ qik.api.post(url, credentials, postOptions).then(function(res) {
454
+
455
+ if (autoAuthenticate) {
456
+ store.user = res.data;
457
+ dispatch();
458
+ }
459
+
460
+ resolve(res);
461
+ }, reject);
462
+ }
463
+
464
+ //////////////////////////////////////
465
+
466
+ return promise;
467
+
468
+ }
469
+
470
+
471
+ ///////////////////////////////////////////////////
472
+
473
+ /**
474
+ * Retrieves a user's details by providing a password reset token
475
+ * @alias auth.retrieveUserFromResetToken
476
+ * @param {String} token The password reset token that was sent to the user's email address
477
+ * @param {Object} options other options for the request
478
+ * @param {Boolean} options.application If true will retrieve in the context of a managed persona in the same organisation as the current application.
479
+ * If not specified or false, will assume it's a Qik global user that is resetting their password.
480
+ * @return {Promise} Returns a promise that resolves with the reset session details
481
+ */
482
+ service.retrieveUserFromResetToken = function(resetToken, options) {
483
+
484
+ if (!options) {
485
+ options = {};
486
+ }
487
+
488
+ //////////////////////////////////////
489
+
490
+ return new Promise(function(resolve, reject) {
491
+
492
+ var postOptions = {
493
+ bypassInterceptor: true
494
+ }
495
+
496
+ /////////////////////////////////////////////
497
+
498
+ //If a full fledged Qik User
499
+ //then send directly to the API auth endpoint
500
+ var url = `${qik.apiURL}/user/reset/${resetToken}`;
501
+
502
+ /////////////////////////////////////////////
503
+
504
+ //If we have a specified url
505
+ if (options.url) {
506
+ url = options.url;
507
+ }
508
+
509
+ /////////////////////////////////////////////
510
+
511
+ qik.api.get(url, postOptions).then(function(res) {
512
+ return resolve(res.data);
513
+ }, reject);
514
+ });
515
+
516
+ }
517
+
518
+
519
+ ///////////////////////////////////////////////////
520
+
521
+ /**
522
+ * Updates a user's details including password by providing a password reset token
523
+ * @alias auth.updateUserWithToken
524
+ * @param {String} token The password reset token that was sent to the user's email address
525
+ * @param {Object} body The details to change for the user
526
+ * @param {Object} options other options for the request
527
+ * @return {Promise} Returns a promise that resolves with the reset session details
528
+ */
529
+ service.updateUserWithToken = function(resetToken, body, options) {
530
+
531
+ if (!options) {
532
+ options = {};
533
+ }
534
+
535
+ //////////////////////////
536
+
537
+ //Change the users current tokens straight away
538
+ var autoAuthenticate = true;
539
+
540
+ if (options.disableAutoAuthentication) {
541
+ autoAuthenticate = false;
542
+ }
543
+
544
+ //////////////////////////////////////
545
+
546
+ return new Promise(function(resolve, reject) {
547
+
548
+ var postOptions = {
549
+ bypassInterceptor: true
550
+ }
551
+
552
+ /////////////////////////////////////////////
553
+
554
+ //If a full fledged Qik User
555
+ //then send directly to the API auth endpoint
556
+ var url = `${qik.apiURL}/user/reset/${resetToken}`;
557
+
558
+ /////////////////////////////////////////////
559
+
560
+ //If we have a specified url
561
+ if (options.url) {
562
+ url = options.url;
563
+ }
564
+
565
+ /////////////////////////////////////////////
566
+
567
+ qik.api.post(url, body, postOptions).then(function(res) {
568
+
569
+ //If we should automatically authenticate
570
+ //once the request is successful
571
+ //Then clear caches and update the session
572
+ if (autoAuthenticate) {
573
+ qik.cache.reset();
574
+ service.set(res.data);
575
+ }
576
+
577
+ return resolve(res.data);
578
+ }, reject);
579
+ });
580
+
581
+ }
582
+
583
+
584
+ ///////////////////////////////////////////////////
585
+
586
+ /**
587
+ * Triggers a new Reset Password email request to the specified user.
588
+ * @alias auth.sendResetPasswordRequest
589
+ * @param {Object} body
590
+ * @param {String} body.email The email address of the user to reset the password for
591
+ * @param {String} body.redirect If the request is in the context of a managed user persona authenticated with an application, then you need to provide the url to direct the user to when they click the reset password link
592
+ * This is usually something like '/reset' for the current application, when the user clicks the link the reset token will be appended with ?token=RESET_TOKEN and your application should
593
+ * be ready on that url to handle the token and allow the user to use the token to reset their password
594
+ * @param {Object} options Extra options and configuration for the request
595
+ * @param {Boolean} options.application If true will send a reset email from the context of a managed persona in the same organisation as the current application.
596
+ * If not specified or false, will send a password reset request for a global Qik user organisation.
597
+ * @return {Promise} Returns a promise that either resolves if the password request was sent, or rejects if an error occurred
598
+ */
599
+ service.sendResetPasswordRequest = function(body, options) {
600
+
601
+ if (!options) {
602
+ options = {};
603
+ }
604
+
605
+ //////////////////////////////////////
606
+
607
+ var promise = new Promise(signupCheck)
608
+
609
+ function signupCheck(resolve, reject) {
610
+
611
+ if (!body) {
612
+ return reject({
613
+ message: 'No details provided',
614
+ })
615
+ }
616
+
617
+ if (!body.email || !body.email.length) {
618
+ return reject({
619
+ message: 'Email was not provided',
620
+ })
621
+ }
622
+
623
+ //Set email as the email address
624
+ body.email = body.email;
625
+
626
+ /////////////////////////////////////////////
627
+
628
+ var postOptions = {
629
+ bypassInterceptor: true
630
+ }
631
+
632
+ /////////////////////////////////////////////
633
+
634
+ //If a full fledged Qik User
635
+ //then send directly to the API
636
+ var url = `${qik.apiURL}/user/forgot`;
637
+
638
+ /////////////////////////////////////////////
639
+
640
+ //If we have a specified url
641
+ if (options.url) {
642
+ url = options.url;
643
+ }
644
+
645
+ /////////////////////////////////////////////
646
+
647
+ qik.api.post(url, body, postOptions).then(resolve, reject);
648
+ }
649
+
650
+ //////////////////////////////////////
651
+
652
+ return promise;
653
+ }
654
+
655
+
656
+ ///////////////////////////////////////////////////
657
+
658
+ /**
659
+ * Helper function to refresh an access token for an authenticated user session. This is usually handled automatically
660
+ * from the QikAuth service itself
661
+ * @alias auth.refreshAccessToken
662
+ * @param {String} refreshToken The refresh token to reactivate
663
+ * @param {Boolean} isManagedSession Whether or not the refresh token is for a managed persona session or a global Qik user session
664
+ * @return {Promise} A promise that either resolves with the refreshed token details or rejects with the responding error from the server
665
+ */
666
+
667
+ const refreshContext = {};
668
+
669
+
670
+ service.refreshAccessToken = function(refreshToken) {
671
+
672
+ // /////////////////////////////////////////////
673
+
674
+ // if (appContext) {
675
+ // console.log('refresh token in app context')
676
+ // } else {
677
+ // console.log('refresh token in normal context')
678
+ // }
679
+
680
+ // /////////////////////////////////////////////
681
+
682
+ //If there is already a request in progress
683
+ if (refreshContext.inflightRefreshRequest) {
684
+ log(`qik.auth > use inflight request`);
685
+ return refreshContext.inflightRefreshRequest;
686
+ }
687
+
688
+ /////////////////////////////////////////////////////
689
+
690
+ //Create an refresh request
691
+ log(`qik.auth > refresh token new request`);
692
+ refreshContext.inflightRefreshRequest = new Promise(function(resolve, reject) {
693
+
694
+
695
+ log(`qik.auth > refresh token ${refreshToken}`);
696
+
697
+ //Bypass the interceptor on all token refresh calls
698
+ //Because we don't need to add the access token etc onto it
699
+ qik.api.post(`/user/refresh`, {
700
+ refreshToken: refreshToken
701
+ }, {
702
+ bypassInterceptor: true,
703
+ })
704
+ .then(function tokenRefreshComplete(res) {
705
+
706
+ //Update the user with any changes
707
+ //returned back from the refresh request
708
+ if (!res) {
709
+ log('qik.auth > no res');
710
+ refreshContext.inflightRefreshRequest = null;
711
+ return reject();
712
+
713
+ } else {
714
+ if (store.user) {
715
+ Object.assign(store.user, res.data);
716
+ } else {
717
+ store.user = res.data;
718
+ }
719
+ log(`qik.auth > token refreshed > ${res.data}`);
720
+
721
+ dispatch();
722
+ }
723
+
724
+ //Resolve with the new token
725
+ resolve(res.data.token);
726
+
727
+ //Remove the inflight request
728
+ setTimeout(function() {
729
+ refreshContext.inflightRefreshRequest = null;
730
+ })
731
+
732
+
733
+ })
734
+ .catch(function(err) {
735
+ console.log('TOKEN REFRESH FAILED', err);
736
+
737
+ //TODO Check if invalid_refresh_token
738
+
739
+ //console.log('Refresh request Failed')
740
+ setTimeout(function() {
741
+ refreshContext.inflightRefreshRequest = null;
742
+ });
743
+ reject(err);
744
+
745
+
746
+
747
+ });
748
+ });
749
+
750
+ //Return the refresh request
751
+ return refreshContext.inflightRefreshRequest;
752
+ }
753
+
754
+
755
+
756
+ ///////////////////////////////////////////////////
757
+
758
+
759
+
760
+ /**
761
+ * Helper function to resync the user's session from the server. This is often used when first loading a webpage or app
762
+ * just to see if the user's permissions have changed since the user first logged in
763
+ * from the QikAuth service itself
764
+ * @alias auth.sync
765
+ * @return {Promise} A promise that either resolves with the user session
766
+ */
767
+
768
+ var retryCount = 0;
769
+
770
+ service.sync = function() {
771
+
772
+ // console.log('Sync with server', store.user)
773
+ return qik.api.get('/user')
774
+ .then(function(res) {
775
+
776
+ // console.log('sync response', res);
777
+
778
+ if (res.data) {
779
+ if (store.user) {
780
+ Object.assign(store.user, res.data);
781
+ }
782
+ } else {
783
+ store.user = null;
784
+ }
785
+ log('qik.auth > server session refreshed');
786
+ retryCount = 0;
787
+
788
+ dispatch();
789
+ })
790
+ .catch(function(err) {
791
+ // if (retryCount > 2) {
792
+ console.log('auth sync not logged in');
793
+ store.user = null;
794
+ retryCount = 0;
795
+ dispatch();
796
+ // } else {
797
+ // console.log('Retry sync')
798
+ // retryCount++;
799
+ // service.sync();
800
+ // }
801
+
802
+
803
+ });
804
+ }
805
+
806
+ /////////////////////////////////////////////////////
807
+
808
+ /**
809
+ * Returns the current user's session data
810
+ * @alias auth.getCurrentUser
811
+ * @return {Object} The current user session
812
+ */
813
+ service.getCurrentUser = function() {
814
+ return store.user;
815
+ }
816
+
817
+
818
+ service.getCurrentToken = function() {
819
+ return service.getCurrentUser().accessToken;
820
+ }
821
+
822
+ /////////////////////////////////////////////////////
823
+
824
+ qik.api.interceptors.request.use(function(config) {
825
+
826
+ //If we want to bypass the interceptor
827
+ //then just return the request
828
+ if (config.bypassInterceptor) {
829
+ console.log('auth interceptor was bypassed');
830
+ return config;
831
+ }
832
+
833
+ //////////////////////////////
834
+ //////////////////////////////
835
+ //////////////////////////////
836
+ //////////////////////////////
837
+
838
+ //Get the original request
839
+ var originalRequest = config;
840
+
841
+ //If we aren't logged in or don't have a token
842
+ var accessToken = _.get(store, 'user.accessToken');
843
+ var refreshToken = _.get(store, 'user.refreshToken');
844
+
845
+ //////////////////////////////
846
+
847
+ //If there is a user token
848
+ if (accessToken) {
849
+ //Set the token of the request as the user's access token
850
+ originalRequest.headers['Authorization'] = `Bearer ${accessToken}`;
851
+ log('qik.auth > using user token');
852
+
853
+ } else {
854
+ //Return the original request without a token
855
+ log('qik.auth > no token');
856
+ return originalRequest;
857
+ }
858
+
859
+ /////////////////////////////////////////////////////
860
+
861
+ //If no refresh token
862
+ if (!refreshToken) {
863
+ log('qik.auth > no refresh token');
864
+
865
+ //Continue with the original request
866
+ return originalRequest;
867
+ }
868
+
869
+ /////////////////////////////////////////////////////
870
+
871
+ //We have a refresh token so we need to check
872
+ //whether our access token is stale and needs to be refreshed
873
+ var now = new Date();
874
+
875
+ //Give us a bit of buffer incase some of our images
876
+ //are still loading
877
+ now.setSeconds(now.getSeconds() + 10);
878
+
879
+ /////////////////////////////////////////////////////
880
+
881
+ var expiryDate = _.get(store, 'user.expires');
882
+ var expires = new Date(expiryDate);
883
+
884
+ //If the token is still fresh
885
+ if (now < expires) {
886
+ //Return the original request
887
+ return originalRequest;
888
+ }
889
+
890
+ /////////////////////////////////////////////////////
891
+
892
+ log('qik.auth > token expired');
893
+
894
+ return new Promise(function(resolve, reject) {
895
+
896
+ //Refresh the token
897
+ service.refreshAccessToken(refreshToken)
898
+ .then(function(newToken) {
899
+ log('qik.auth > token refreshed', isManagedUser);
900
+ //Update the original request with our new token
901
+ originalRequest.headers['Authorization'] = `Bearer ${newToken}`;
902
+ //And continue onward
903
+ return resolve(originalRequest);
904
+ })
905
+ .catch(function(err) {
906
+ console.log('ERRRRRR', err);
907
+ log('qik.auth > token refresh rejected', err);
908
+ return reject(err);
909
+ });
910
+ });
911
+
912
+
913
+ }, function(error) {
914
+ return Promise.reject(error);
915
+ })
916
+
917
+ /////////////////////////////////////////////////////
918
+
919
+ qik.api.interceptors.response.use(function(response) {
920
+ return response;
921
+ }, function(err) {
922
+
923
+ //////////////////////////////
924
+
925
+ //Get the response status
926
+ var status = _.get(err, 'response.status') || err.status;
927
+
928
+ log('qik.auth > error', status);
929
+ switch (status) {
930
+ case 401:
931
+ console.log('logout from 401')
932
+ service.logout();
933
+ break;
934
+ default:
935
+ //Some other error
936
+ break;
937
+ }
938
+
939
+ /////////////////////////////////////////////////////
940
+
941
+ return Promise.reject(err);
942
+ })
943
+
944
+
945
+ /**
946
+ * @name auth.addEventListener
947
+ * @description Adds a callback that will be triggered whenever the specified event occurs
948
+ * @function
949
+ * @param {String} event The event to listen for
950
+ * @param {Function} callback The function to fire when this event is triggered
951
+ * @example
952
+ * //Listen for when the user session changes
953
+ * qik.auth.addEventListener('change', function(userSession) {})
954
+ */
955
+
956
+ /**
957
+ * @name auth.removeEventListener
958
+ * @description Removes all a callback from the listener list
959
+ * @function
960
+ * @param {String} event The event to stop listening for
961
+ * @param {Function} callback The function to remove from the listener list
962
+ * @example
963
+ * //Stop listening for the change event
964
+ * qik.auth.removeEventListener('change', myFunction)
965
+ */
966
+
967
+ /**
968
+ * @name auth.removeAllListeners
969
+ * @description Removes all listening callbacks for all events
970
+ * @function
971
+ * @example
972
+ * qik.auth.removeAllListeners()
973
+ */
974
+
975
+ return service;
976
+
977
+ }
978
+
979
+
980
+ export default QikAuth;