Skip to content

Commit 38faa47

Browse files
fix(oauth2): replace localStorage with sessionStorage in callback component (#2790)
1 parent 8cea62a commit 38faa47

File tree

3 files changed

+60
-53
lines changed

3 files changed

+60
-53
lines changed

src/app/zitadel/auth.service.ts

Lines changed: 40 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export class AuthService {
3333
async login() {
3434
const codeVerifier = this.generateRandomString();
3535
const codeChallenge = await this.generateCodeChallenge(codeVerifier);
36-
localStorage.setItem('code_verifier', codeVerifier);
36+
sessionStorage.setItem('code_verifier', codeVerifier);
3737
const url =
3838
`${this.authUrl}` +
3939
`?client_id=${encodeURIComponent(this.clientId)}` +
@@ -105,56 +105,51 @@ export class AuthService {
105105
return base64;
106106
}
107107

108-
exchangeCodeForTokens(code: string, codeVerifier: string | null) {
108+
async exchangeCodeForTokens(code: string, codeVerifier: string | null): Promise<void> {
109109
const payload = {
110110
code: code,
111111
code_verifier: codeVerifier || ''
112112
};
113113

114-
fetch(this.api + 'authentication/token', {
115-
method: 'POST',
116-
headers: {
117-
'Content-Type': 'application/json'
118-
},
119-
body: JSON.stringify(payload)
120-
})
121-
.then((res) => {
122-
if (!res.ok) {
123-
throw new Error(`Error exchanging code: ${res.status} ${res.statusText}`);
124-
}
125-
return res.json();
126-
})
127-
.then(
128-
(tokens: {
129-
access_token: string;
130-
id_token: string;
131-
refresh_token: string;
132-
expires_in: number;
133-
token_type: string;
134-
}) => {
135-
const token: OAuth2Token = {
136-
access_token: tokens.access_token,
137-
token_type: tokens.token_type,
138-
refresh_token: tokens.refresh_token,
139-
expires_in: tokens.expires_in,
140-
scope: 'Bearer'
141-
};
142-
143-
localStorage.setItem('id_token', tokens.id_token);
144-
localStorage.setItem('mifosXZitadel', 'true');
145-
sessionStorage.setItem('mifosXZitadelTokenDetails', JSON.stringify(token));
146-
localStorage.setItem('refresh_token', tokens.refresh_token);
147-
this.scheduleRefresh(tokens.expires_in);
148-
localStorage.removeItem('auth_code');
149-
localStorage.removeItem('code_verifier');
150-
this.userdetails();
151-
}
152-
)
153-
.catch((error) => {
154-
localStorage.removeItem('auth_code');
155-
localStorage.removeItem('code_verifier');
156-
window.location.href = '/#/login';
114+
try {
115+
const response = await fetch(this.api + 'authentication/token', {
116+
method: 'POST',
117+
headers: {
118+
'Content-Type': 'application/json'
119+
},
120+
body: JSON.stringify(payload)
157121
});
122+
123+
if (!response.ok) {
124+
throw new Error(`Error exchanging code: ${response.status} ${response.statusText}`);
125+
}
126+
127+
const tokens: {
128+
access_token: string;
129+
id_token: string;
130+
refresh_token: string;
131+
expires_in: number;
132+
token_type: string;
133+
} = await response.json();
134+
135+
const token: OAuth2Token = {
136+
access_token: tokens.access_token,
137+
token_type: tokens.token_type,
138+
refresh_token: tokens.refresh_token,
139+
expires_in: tokens.expires_in,
140+
scope: 'Bearer'
141+
};
142+
143+
sessionStorage.setItem('mifosXZitadelTokenDetails', JSON.stringify(token));
144+
localStorage.setItem('id_token', tokens.id_token);
145+
localStorage.setItem('refresh_token', tokens.refresh_token);
146+
localStorage.setItem('mifosXZitadel', 'true');
147+
this.scheduleRefresh(tokens.expires_in);
148+
await this.userdetails();
149+
} catch (error) {
150+
window.location.href = '/#/login';
151+
throw error;
152+
}
158153
}
159154

160155
userdetails() {
Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Component, OnInit } from '@angular/core';
2-
import { ActivatedRoute } from '@angular/router';
2+
import { ActivatedRoute, Router } from '@angular/router';
33
import { AuthService } from '../auth.service';
44

55
@Component({
@@ -9,15 +9,27 @@ import { AuthService } from '../auth.service';
99
export class CallbackComponent implements OnInit {
1010
constructor(
1111
private route: ActivatedRoute,
12+
private router: Router,
1213
private authService: AuthService
1314
) {}
1415

15-
ngOnInit(): void {
16-
let code = localStorage.getItem('auth_code');
17-
18-
if (code) {
19-
const codeVerifier = localStorage.getItem('code_verifier');
20-
this.authService.exchangeCodeForTokens(code, codeVerifier);
16+
async ngOnInit(): Promise<void> {
17+
try {
18+
const code = sessionStorage.getItem('auth_code');
19+
if (code) {
20+
const codeVerifier = sessionStorage.getItem('code_verifier');
21+
try {
22+
await this.authService.exchangeCodeForTokens(code, codeVerifier);
23+
} finally {
24+
// Clean up sensitive data immediately after use
25+
sessionStorage.removeItem('auth_code');
26+
sessionStorage.removeItem('code_verifier');
27+
}
28+
}
29+
} catch (error) {
30+
console.error('Authentication failed:', error);
31+
// Navigate to login page
32+
this.router.navigate(['/login']);
2133
}
2234
}
2335
}

src/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
}
2626
const code = getQueryParam('code');
2727
if (code) {
28-
localStorage.setItem('auth_code', code);
28+
sessionStorage.setItem('auth_code', code);
2929
window.location.href = '/#/callback';
3030
}
3131
</script>

0 commit comments

Comments
 (0)