Repository: auth0/auth0-spa-js
Pull request #471 (2020-05-19 09:43:59)

[SDK-1640] Allow the client to be constructed in a Node SSR environment
### Description

To make it easier to use in SSR apps like Gatsby/NextJS. Add some guards around browser specific parts of the client constructor so that users can instantiate the class and check auth state without throwing errors.

```
const client = new Auth0Client({ ... });
const isAuthenticated = await client.isAuthenticated(); // false in SSR
const user = await client.getUser(); // undefined in SSR
```
(calling login, etc. will still throw errors)

### Testing

- [ ] This change adds test coverage for new/changed/fixed functionality

### Checklist

- [ ] I have added documentation for new/changed functionality in this PR or in auth0.com/docs
- [ ] All active GitHub checks for tests, formatting, and security are passing
- [ ] The correct base branch is being used, if not `master`



Patch:
diff --git a/src/Auth0Client.ts b/src/Auth0Client.ts
index 9d8da5f..81856d7 100644
--- a/src/Auth0Client.ts
+++ b/src/Auth0Client.ts
@@ -96,7 +96,7 @@ export default class Auth0Client {
   private worker: Worker;
 
   constructor(private options: Auth0ClientOptions) {
-    validateCrypto();
+    typeof window !== 'undefined' && validateCrypto();
     this.cacheLocation = options.cacheLocation || CACHE_LOCATION_MEMORY;
 
     if (!cacheFactory(this.cacheLocation)) {
@@ -128,6 +128,7 @@ export default class Auth0Client {
 
     // Don't use web workers unless using refresh tokens in memory and not IE11
     if (
+      typeof window !== 'undefined' &&
       window.Worker &&
       this.options.useRefreshTokens &&
       this.cacheLocation === CACHE_LOCATION_MEMORY &&
diff --git a/src/transaction-manager.ts b/src/transaction-manager.ts
index f9ebf30..c0ddf2c 100644
--- a/src/transaction-manager.ts
+++ b/src/transaction-manager.ts
@@ -18,12 +18,13 @@ export default class TransactionManager {
   private transactions: Transactions;
   constructor() {
     this.transactions = {};
-    ClientStorage.getAllKeys()
-      .filter(k => k.startsWith(COOKIE_KEY))
-      .forEach(k => {
-        const state = k.replace(COOKIE_KEY, '');
-        this.transactions[state] = ClientStorage.get<Transaction>(k);
-      });
+    typeof window !== 'undefined' &&
+      ClientStorage.getAllKeys()
+        .filter(k => k.startsWith(COOKIE_KEY))
+        .forEach(k => {
+          const state = k.replace(COOKIE_KEY, '');
+          this.transactions[state] = ClientStorage.get<Transaction>(k);
+        });
   }
   public create(state: string, transaction: Transaction) {
     this.transactions[state] = transaction;


Test patch:
diff --git a/__tests__/ssr.test.ts b/__tests__/ssr.test.ts
new file mode 100644
index 0000000..0d3fdc6
--- /dev/null
+++ b/__tests__/ssr.test.ts
@@ -0,0 +1,18 @@
+/**
+ * @jest-environment node
+ */
+import Auth0Client from '../src/Auth0Client';
+
+describe('In a Node SSR environment', () => {
+  it('can be constructed', () => {
+    expect(
+      () => new Auth0Client({ client_id: 'foo', domain: 'bar' })
+    ).not.toThrow();
+  });
+
+  it('can check authenticated state', async () => {
+    const client = new Auth0Client({ client_id: 'foo', domain: 'bar' });
+    expect(await client.isAuthenticated()).toBeFalsy();
+    expect(await client.getUser()).toBeUndefined();
+  });
+});