1- import axios from 'axios'
1+ import axios , { AxiosError } from 'axios'
22import { IAuthManager , DIDAuthConfig , KeyValueStore , PersonalSign } from './types'
33import { LocalStorage } from './store'
44
5- const xCsrfToken = 'x-csrf-token'
5+ const XCsrfToken = 'x-csrf-token'
66
77class AuthManager implements IAuthManager {
88 store : KeyValueStore
@@ -20,20 +20,16 @@ class AuthManager implements IAuthManager {
2020 }
2121
2222 private saveCsrf = async ( response ) => {
23- const token = await this . store . get ( xCsrfToken )
24-
25- if ( ! token ) {
26- await this . store . set ( xCsrfToken , response . headers [ xCsrfToken ] )
27- }
28-
23+ const xCsrfToken = await this . store . get ( XCsrfToken )
24+ if ( ! xCsrfToken && response . headers [ XCsrfToken ] ) await this . store . set ( XCsrfToken , response . headers [ XCsrfToken ] )
2925 return response
3026 }
3127
3228 // did auth challenge-response authentication
3329 private getChallenge = ( ) : Promise < string > => axios . get ( `${ this . serviceUrl } /request-auth/${ this . did } ` )
3430 . catch ( e => this . saveCsrf ( e . response ) )
3531 . then ( res => {
36- this . store . set ( xCsrfToken , res . headers [ xCsrfToken ] )
32+ this . store . set ( XCsrfToken , res . headers [ XCsrfToken ] )
3733 return res . data . challenge
3834 } )
3935 . then ( this . saveCsrf )
@@ -42,19 +38,18 @@ class AuthManager implements IAuthManager {
4238 `Are you sure you want to login to the RIF Data Vault?\nURL: ${ this . serviceUrl } \nVerification code: ${ challenge } `
4339 ) . then ( sig => ( { did : this . did , sig } ) )
4440
45- private login = ( ) : Promise < void > => this . store . get ( xCsrfToken )
41+ private login = ( ) : Promise < void > => this . store . get ( XCsrfToken )
4642 . then ( token => this . getChallenge ( )
4743 . then ( this . signChallenge )
4844 . then ( signature => axios . post ( `${ this . serviceUrl } /auth` , { response : signature } , {
4945 headers : { 'x-csrf-token' : token }
5046 } ) ) )
5147
52- private getConfig = ( ) => this . store . get ( xCsrfToken ) . then ( token => ( {
53- headers : {
54- 'x-csrf-token' : token ,
55- 'x-logged-did' : this . did
56- }
57- } ) )
48+ private getConfig = ( ) => this . store . get ( XCsrfToken ) . then ( xCsrfToken => {
49+ const headers = { 'x-logged-did' : this . did }
50+ if ( xCsrfToken ) headers [ XCsrfToken ] = xCsrfToken
51+ return { headers }
52+ } )
5853
5954 private async refreshAccessToken ( ) : Promise < void > {
6055 const config = await this . getConfig ( )
@@ -67,18 +62,29 @@ class AuthManager implements IAuthManager {
6762 }
6863 }
6964
65+ private handleRequestError = ( method : any , ...args ) => ( error : AxiosError ) => {
66+ if ( error . response . status === 401 ) {
67+ return this . saveCsrf ( error . response )
68+ . then ( ( ) => this . refreshAccessToken ( ) )
69+ . then ( ( ) => this . getConfig ( ) )
70+ . then ( config => method ( config , ...args ) )
71+ }
72+ if ( error . response . status === 403 ) {
73+ return this . get ( `${ this . serviceUrl } /refresh-csrf` )
74+ . then ( res => this . store . set ( XCsrfToken , res . data ) )
75+ . then ( ( ) => this . getConfig ( ) )
76+ . then ( config => method ( config , ...args ) )
77+ }
78+ throw error
79+ }
80+
7081 private request = ( method : any ) => async ( ...args ) => {
7182 const config = await this . getConfig ( )
83+ const handleRequestError = this . handleRequestError ( method , ...args )
7284 return await method ( config , ...args )
7385 . then ( r => r as any )
74- . catch ( e => {
75- if ( e . response . status === 401 ) {
76- return this . saveCsrf ( e . response )
77- . then ( ( ) => this . refreshAccessToken ( ) )
78- . then ( ( ) => method ( config , ...args ) )
79- }
80- throw e
81- } )
86+ . catch ( handleRequestError )
87+ . catch ( handleRequestError ) // retries twice. reason: we can have 403 error followed by a 401 error
8288 }
8389
8490 get : typeof axios . get = this . request ( ( config , ...args ) => axios . get ( args [ 0 ] , config ) )
0 commit comments