@@ -9,6 +9,12 @@ enum LoginType {
99 Redirect ,
1010}
1111
12+ enum AuthenticationState {
13+ Unauthenticated ,
14+ Authenticating ,
15+ Authenticated ,
16+ }
17+
1218type UserInfoCallback = ( token : IUserInfo ) => void ;
1319
1420type UnauthenticatedFunction = ( login : LoginFunction ) => JSX . Element ;
@@ -31,8 +37,7 @@ interface IProps {
3137}
3238
3339interface IState {
34- authenticated : boolean ,
35- userInfo : IUserInfo | null ,
40+ authenticationState : AuthenticationState ,
3641}
3742
3843interface IUserInfo {
@@ -41,44 +46,71 @@ interface IUserInfo {
4146 user : Msal . User ,
4247}
4348
49+ interface IRedirectLogin {
50+ error : string ,
51+ errorDesc : string ,
52+ idToken : string ,
53+ tokenType : string ,
54+ }
55+
4456class AzureAD extends React . Component < IProps , IState > {
4557
4658 private clientApplication : Msal . UserAgentApplication ;
59+ private redirectLoginInfo : IRedirectLogin ;
4760
4861 constructor ( props : IProps ) {
4962 super ( props ) ;
63+
64+ let authenticationState = AuthenticationState . Unauthenticated ;
5065 this . clientApplication = new Msal . UserAgentApplication (
5166 props . clientID ,
52- props . authority ? props . authority : null ,
53- this . loginRedirect
67+ props . authority ? props . authority : null ,
68+ ( errorDesc : string , idToken : string , error : string , tokenType : string ) => {
69+ this . redirectLoginInfo = {
70+ error,
71+ errorDesc,
72+ idToken,
73+ tokenType
74+ }
75+ authenticationState = AuthenticationState . Authenticating ;
76+ }
5477 ) ;
55- this . state = {
56- authenticated : false ,
57- userInfo : null ,
58- } ;
78+
79+ this . state = { authenticationState } ;
5980 }
6081
6182 public render ( ) {
62- if ( ! this . state . authenticated ) {
63- return this . props . unauthenticatedFunction ( this . login ) ;
83+ switch ( this . state . authenticationState ) {
84+ case AuthenticationState . Authenticated :
85+ return this . props . authenticatedFunction ( this . logout ) ;
86+ case AuthenticationState . Authenticating :
87+ // TODO: Add loading callback, componentDidMount will acquire tokens and then re-render
88+ return null ;
89+ case AuthenticationState . Unauthenticated :
90+ default :
91+ return this . props . unauthenticatedFunction ( this . login ) ;
6492 }
65- return this . props . authenticatedFunction ( this . logout ) ;
6693 }
6794
68- public createUserInfo = ( accessToken : string , idToken : string , msalUser : Msal . User ) : IUserInfo => {
95+ public componentDidMount ( ) {
96+ if ( this . redirectLoginInfo ) {
97+ if ( this . redirectLoginInfo . idToken ) {
98+ this . acquireTokens ( this . redirectLoginInfo . idToken ) ;
99+ }
100+ else if ( this . redirectLoginInfo . errorDesc || this . redirectLoginInfo . error ) {
101+ Logger . error ( `Error doing login redirect; errorDescription=${ this . redirectLoginInfo . errorDesc } , error=${ this . redirectLoginInfo . error } ` ) ;
102+ }
103+ }
104+ }
105+
106+ public createUserInfo = ( accessToken : string , idToken : string , msalUser : Msal . User ) : void => {
69107 const user : IUserInfo = {
70108 jwtAccessToken : accessToken ,
71109 jwtIdToken : idToken ,
72110 user : msalUser
73111 } ;
74- this . setState ( {
75- authenticated : true ,
76- userInfo : user
77- } ) ;
78-
112+ this . props . userInfoCallback ( user ) ;
79113 this . dispatchToProvidedReduxStore ( user ) ;
80-
81- return user ;
82114 }
83115
84116 public resetUserInfo = ( ) => {
@@ -87,25 +119,18 @@ class AzureAD extends React.Component<IProps, IState> {
87119 }
88120
89121 this . setState ( {
90- authenticated : false ,
91- userInfo : null
122+ authenticationState : AuthenticationState . Unauthenticated ,
92123 } ) ;
93124 }
94125
95- private loginRedirect = ( errorDesc : string , idToken : string , error : string , tokenType : string ) => {
96- if ( idToken ) {
97- this . acquireTokens ( idToken ) ;
98- }
99- else if ( errorDesc || error ) {
100- Logger . error ( `Error doing login redirect; errorDescription=${ errorDesc } , error=${ error } ` ) ;
101- }
102- }
103-
104126 private acquireTokens = ( idToken : string ) => {
105127 this . clientApplication . acquireTokenSilent ( this . props . scopes )
106128 . then ( ( accessToken : string ) => {
107- const user = this . createUserInfo ( accessToken , idToken , this . clientApplication . getUser ( ) ) ;
108- this . props . userInfoCallback ( user ) ;
129+ this . createUserInfo ( accessToken , idToken , this . clientApplication . getUser ( ) ) ;
130+
131+ this . setState ( {
132+ authenticationState : AuthenticationState . Authenticated ,
133+ } ) ;
109134 } , ( tokenSilentError ) => {
110135 Logger . error ( `token silent error; ${ tokenSilentError } ` ) ;
111136 this . clientApplication . acquireTokenPopup ( this . props . scopes )
@@ -131,11 +156,12 @@ class AzureAD extends React.Component<IProps, IState> {
131156 } ;
132157
133158 private logout = ( ) => {
134- if ( ! this . state . authenticated ) { return ; }
135- else {
136- this . resetUserInfo ( ) ;
137- this . clientApplication . logout ( ) ;
159+ if ( this . state . authenticationState !== AuthenticationState . Authenticated ) {
160+ return ;
138161 }
162+
163+ this . resetUserInfo ( ) ;
164+ this . clientApplication . logout ( ) ;
139165 } ;
140166
141167 private dispatchToProvidedReduxStore ( data : IUserInfo ) {
@@ -145,5 +171,5 @@ class AzureAD extends React.Component<IProps, IState> {
145171 }
146172}
147173
148- export { AzureAD , LoginType , IUserInfo , UnauthenticatedFunction , LoginFunction , AAD_LOGIN_SUCCESS } ;
174+ export { AzureAD , AuthenticationState , LoginType , IUserInfo , UnauthenticatedFunction , LoginFunction , AAD_LOGIN_SUCCESS } ;
149175export default AzureAD ;
0 commit comments