You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat: introduce experimental split user and session storage (#1023)
A common complaint when using Supabase in SSR is that the cookie size is
huge. Some server configurations are not able to use such large cookies.
A major contributor to cookie size is that the user object is stored
alongside the access and refresh tokens. This object _should not be used
on the server_ but nevertheless has to exist to make this library happy.
This change introduces the ability for this library to store the user
object in a separate storage location. For now it's experimental mode to
be proofed before being widely adopted.
**How does it work?**
You can initialize the client by passing in a new option `userStorage`
in addition to the already existing and optional `storage` option. By
default `userStorage` is not set and a single storage is used for all
elements of the session (including `user` property).
If `userStorage` is set, **all future changes to the session** will
write the user there, and the rest of the session object to `storage`.
**Unsolvable Problems**
Say you set up the client like so:
```typescript
new GoTrueClient(URL, {
// ...
storage: cookieStorage,
userStorage: window.localStorage,
})
```
On the server, the cookies -- obviously -- will not contain the `user`
object. Because the `Session` type defines `user: User` as non-nullable,
attempting to access a property on this object will throw an exception.
Instead you should always call `getUser()` to fetch a trusted and fresh
user object. This problem will be solved in v3 of this library.
**Testing**
[This PR](supabase/supabase#32833) can be used
to test this PR before merging. Merging should be safe as this is opt-in
behavior for now.
---------
Co-authored-by: Cemal Kilic <[email protected]>
Co-authored-by: Cemal Kılıç <[email protected]>
@@ -365,3 +365,41 @@ export function validateUUID(str: string) {
365
365
thrownewError('@supabase/auth-js: Expected parameter to be UUID but is not')
366
366
}
367
367
}
368
+
369
+
exportfunctionuserNotAvailableProxy(): User{
370
+
constproxyTarget={}asUser
371
+
372
+
returnnewProxy(proxyTarget,{
373
+
get: (target: any,prop: string)=>{
374
+
if(prop==='__isUserNotAvailableProxy'){
375
+
returntrue
376
+
}
377
+
// Preventative check for common problematic symbols during cloning/inspection
378
+
// These symbols might be accessed by structuredClone or other internal mechanisms.
379
+
if(typeofprop==='symbol'){
380
+
constsProp=(propassymbol).toString()
381
+
if(
382
+
sProp==='Symbol(Symbol.toPrimitive)'||
383
+
sProp==='Symbol(Symbol.toStringTag)'||
384
+
sProp==='Symbol(util.inspect.custom)'
385
+
){
386
+
// Node.js util.inspect
387
+
returnundefined
388
+
}
389
+
}
390
+
thrownewError(
391
+
`@supabase/auth-js: client was created with userStorage option and there was no user stored in the user storage. Accessing the "${prop}" property of the session object is not supported. Please use getUser() instead.`
392
+
)
393
+
},
394
+
set: (_target: any,prop: string)=>{
395
+
thrownewError(
396
+
`@supabase/auth-js: client was created with userStorage option and there was no user stored in the user storage. Setting the "${prop}" property of the session object is not supported. Please use getUser() to fetch a user object you can manipulate.`
397
+
)
398
+
},
399
+
deleteProperty: (_target: any,prop: string)=>{
400
+
thrownewError(
401
+
`@supabase/auth-js: client was created with userStorage option and there was no user stored in the user storage. Deleting the "${prop}" property of the session object is not supported. Please use getUser() to fetch a user object you can manipulate.`
Copy file name to clipboardExpand all lines: src/lib/types.ts
+12Lines changed: 12 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -70,6 +70,14 @@ export type GoTrueClientOptions = {
70
70
persistSession?: boolean
71
71
/* Provide your own local storage implementation to use instead of the browser's local storage. */
72
72
storage?: SupportedStorage
73
+
/**
74
+
* Stores the user object in a separate storage location from the rest of the session data. When non-null, `storage` will only store a JSON object containing the access and refresh token and some adjacent metadata, while `userStorage` will only contain the user object under the key `storageKey + '-user'`.
75
+
*
76
+
* When this option is set and cookie storage is used, `getSession()` and other functions that load a session from the cookie store might not return back a user. It's very important to always use `getUser()` to fetch a user object in those scenarios.
77
+
*
78
+
* @experimental
79
+
*/
80
+
userStorage?: SupportedStorage
73
81
/* A custom fetch implementation. */
74
82
fetch?: Fetch
75
83
/* If set to 'pkce' PKCE flow. Defaults to the 'implicit' flow otherwise */
@@ -253,6 +261,10 @@ export interface Session {
253
261
*/
254
262
expires_at?: number
255
263
token_type: string
264
+
265
+
/**
266
+
* When using a separate user storage, accessing properties of this object will throw an error.
0 commit comments