Skip to content

Commit 9fc994d

Browse files
fix: [PDI-3249] - Use sessionStorage for codeVerifier and nonce: update OAuth and storage (#13570)
* Use sessionStorage for codeVerifier: update OAuth and storage * update * Added changeset: Login issue: Use sessionStorage for codeVerifier and nonce * Remove alert and fix ts errors * Remove alert and fix ts errors * Update AuthenticationError message * Update the test references to use session storage instead of local storage for the code verifier and nonce --------- Co-authored-by: pmakode-akamai <pmakode@akamai.com>
1 parent 0180606 commit 9fc994d

4 files changed

Lines changed: 42 additions & 17 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@linode/manager": Fixed
3+
---
4+
5+
Login issue: Use sessionStorage for codeVerifier and nonce ([#13570](https://github.com/linode/manager/pull/13570))

packages/manager/src/OAuth/oauth.test.tsx

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -78,10 +78,10 @@ describe('generateOAuthAuthorizeEndpoint', () => {
7878
expect(url).toContain('code_challenge=');
7979
});
8080

81-
it('generates a "state" (aka nonce), stores it in local storage, and includes it in the url', async () => {
81+
it('generates a "state" (aka nonce), stores it in session storage, and includes it in the url', async () => {
8282
storage.authentication.nonce.clear();
8383

84-
expect(storage.authentication.nonce.get()).toBeNull();
84+
expect(storage.authentication.nonce.get()).toBeUndefined();
8585

8686
const url = await generateOAuthAuthorizeEndpoint('/linodes');
8787

@@ -91,10 +91,10 @@ describe('generateOAuthAuthorizeEndpoint', () => {
9191
expect(url).toContain(`state=${nonceInStorage}`);
9292
});
9393

94-
it('generates a code verifier and stores it in local storage', async () => {
94+
it('generates a code verifier and stores it in session storage', async () => {
9595
storage.authentication.codeVerifier.clear();
9696

97-
expect(storage.authentication.codeVerifier.get()).toBeNull();
97+
expect(storage.authentication.codeVerifier.get()).toBeUndefined();
9898

9999
await generateOAuthAuthorizeEndpoint('/linodes');
100100

@@ -126,19 +126,19 @@ describe('handleOAuthCallback', () => {
126126
).rejects.toThrowError('Error parsing search params on OAuth callback.');
127127
});
128128

129-
it('should throw if there is no code verifier found in local storage', async () => {
129+
it('should throw if there is no code verifier found in session storage', async () => {
130130
storage.authentication.codeVerifier.clear();
131131

132132
await expect(
133133
handleOAuthCallback({
134134
params: 'state=fehgefhgkefghk&code=gyuwyutfetyfew',
135135
})
136136
).rejects.toThrowError(
137-
'No code codeVerifier found in local storage when running OAuth callback.'
137+
'No code codeVerifier found in session storage when running OAuth callback.'
138138
);
139139
});
140140

141-
it('should throw if there is no nonce found in local storage', async () => {
141+
it('should throw if there is no nonce found in session storage', async () => {
142142
storage.authentication.codeVerifier.set('fakecodeverifier');
143143
storage.authentication.nonce.clear();
144144

@@ -147,11 +147,11 @@ describe('handleOAuthCallback', () => {
147147
params: 'state=fehgefhgkefghk&code=gyuwyutfetyfew',
148148
})
149149
).rejects.toThrowError(
150-
'No nonce found in local storage when running OAuth callback.'
150+
'No nonce found in session storage when running OAuth callback.'
151151
);
152152
});
153153

154-
it('should throw if the nonce in local storage does not match the "state" sent back by login', async () => {
154+
it('should throw if the nonce in session storage does not match the "state" sent back by login', async () => {
155155
storage.authentication.codeVerifier.set('fakecodeverifier');
156156
storage.authentication.nonce.set('fakenonce');
157157

packages/manager/src/OAuth/oauth.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ export async function handleOAuthCallback(options: AuthCallbackOptions) {
207207

208208
if (!codeVerifier) {
209209
throw new AuthenticationError(
210-
'No code codeVerifier found in local storage when running OAuth callback.'
210+
'No code codeVerifier found in session storage when running OAuth callback.'
211211
);
212212
}
213213

@@ -217,7 +217,7 @@ export async function handleOAuthCallback(options: AuthCallbackOptions) {
217217

218218
if (!storedNonce) {
219219
throw new AuthenticationError(
220-
'No nonce found in local storage when running OAuth callback.'
220+
'No nonce found in session storage when running OAuth callback.'
221221
);
222222
}
223223

packages/manager/src/utilities/storage.ts

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import type { StackScriptPayload } from '@linode/api-v4/lib/stackscripts/types';
55
import type { SupportTicketFormFields } from 'src/features/Support/SupportTickets/SupportTicketDialog';
66

77
const localStorageCache: Record<string, any> = {};
8+
const sessionStorageCache: Record<string, any> = {};
89

910
export const getStorage = (key: string, fallback?: any) => {
1011
if (localStorageCache[key]) {
@@ -48,6 +49,25 @@ export const clearStorage = (key: string) => {
4849
window.localStorage.removeItem(key);
4950
};
5051

52+
export const getSessionStorage = (key: string): string | undefined => {
53+
if (key in sessionStorageCache) {
54+
return sessionStorageCache[key];
55+
}
56+
const item = window.sessionStorage.getItem(key);
57+
sessionStorageCache[key] = item ?? undefined;
58+
return item ?? undefined;
59+
};
60+
61+
export const setSessionStorage = (key: string, value: string) => {
62+
sessionStorageCache[key] = value;
63+
window.sessionStorage.setItem(key, value);
64+
};
65+
66+
export const clearSessionStorage = (key: string) => {
67+
delete sessionStorageCache[key];
68+
window.sessionStorage.removeItem(key);
69+
};
70+
5171
const PAGE_SIZE = 'PAGE_SIZE';
5272
const INFINITE_PAGE_SIZE = 'INFINITE_PAGE_SIZE';
5373
const TOKEN = 'authentication/token';
@@ -150,19 +170,19 @@ export interface Storage {
150170
export const storage: Storage = {
151171
authentication: {
152172
codeVerifier: {
153-
get: () => getStorage(CODE_VERIFIER),
154-
set: (v) => setStorage(CODE_VERIFIER, v),
155-
clear: () => clearStorage(CODE_VERIFIER),
173+
get: () => getSessionStorage(CODE_VERIFIER),
174+
set: (v) => setSessionStorage(CODE_VERIFIER, v),
175+
clear: () => clearSessionStorage(CODE_VERIFIER),
156176
},
157177
expire: {
158178
get: () => getStorage(EXPIRE),
159179
set: (v) => setStorage(EXPIRE, v),
160180
clear: () => clearStorage(EXPIRE),
161181
},
162182
nonce: {
163-
get: () => getStorage(NONCE),
164-
set: (v) => setStorage(NONCE, v),
165-
clear: () => clearStorage(NONCE),
183+
get: () => getSessionStorage(NONCE),
184+
set: (v) => setSessionStorage(NONCE, v),
185+
clear: () => clearSessionStorage(NONCE),
166186
},
167187
scopes: {
168188
get: () => getStorage(SCOPES),

0 commit comments

Comments
 (0)