diff --git a/apps/dotcom/client/src/components/LoginRedirectPage/LoginRedirectPage.tsx b/apps/dotcom/client/src/components/LoginRedirectPage/LoginRedirectPage.tsx
new file mode 100644
index 000000000000..4e73ce71c04b
--- /dev/null
+++ b/apps/dotcom/client/src/components/LoginRedirectPage/LoginRedirectPage.tsx
@@ -0,0 +1,25 @@
+import { ClerkProvider, useClerk } from '@clerk/clerk-react'
+
+export default function LoginRedirectPage() {
+ // @ts-ignore this is fine
+ const PUBLISHABLE_KEY = import.meta.env.VITE_CLERK_PUBLISHABLE_KEY
+
+ if (!PUBLISHABLE_KEY) {
+ throw new Error('Missing VITE_CLERK_PUBLISHABLE_KEY in .env.local')
+ }
+
+ return (
+
+
+
+ )
+}
+
+function LoginRedirectPageInner() {
+ const clerk = useClerk()
+
+ const signInUrl = clerk.buildSignInUrl({ signInForceRedirectUrl: window.location.href })
+ window.location.href = signInUrl
+
+ return null
+}
diff --git a/apps/dotcom/client/src/components/StoreErrorScreen.tsx b/apps/dotcom/client/src/components/StoreErrorScreen.tsx
index 42c3f5fec15e..9a9d33307b19 100644
--- a/apps/dotcom/client/src/components/StoreErrorScreen.tsx
+++ b/apps/dotcom/client/src/components/StoreErrorScreen.tsx
@@ -1,9 +1,11 @@
import { TLRemoteSyncError, TLSyncErrorCloseEventReason } from '@tldraw/sync-core'
import { ErrorPage } from './ErrorPage/ErrorPage'
+import LoginRedirectPage from './LoginRedirectPage/LoginRedirectPage'
export function StoreErrorScreen({ error }: { error: Error }) {
let header = 'Could not connect to server.'
let message = ''
+
if (error instanceof TLRemoteSyncError) {
switch (error.reason) {
case TLSyncErrorCloseEventReason.CLIENT_TOO_OLD: {
@@ -41,10 +43,12 @@ export function StoreErrorScreen({ error }: { error: Error }) {
message = 'The room you are trying to connect to does not exist.'
break
}
- case TLSyncErrorCloseEventReason.NOT_AUTHENTICATED:
+ case TLSyncErrorCloseEventReason.NOT_AUTHENTICATED: {
+ return
+ }
case TLSyncErrorCloseEventReason.FORBIDDEN: {
- header = 'Unauthorized'
- message = 'You need to be authorized to view this room.'
+ header = 'Forbidden'
+ message = 'You are forbidden to view this room.'
break
}
default: {
diff --git a/apps/dotcom/client/src/routes.tsx b/apps/dotcom/client/src/routes.tsx
index 289c9b565573..e0adeecac54e 100644
--- a/apps/dotcom/client/src/routes.tsx
+++ b/apps/dotcom/client/src/routes.tsx
@@ -6,11 +6,13 @@ import {
SNAPSHOT_PREFIX,
} from '@tldraw/dotcom-shared'
import { TLRemoteSyncError, TLSyncErrorCloseEventReason } from '@tldraw/sync-core'
-import { useEffect } from 'react'
-import { Link, Route, createRoutesFromElements, useRouteError } from 'react-router-dom'
+import { Suspense, lazy, useEffect } from 'react'
+import { Route, createRoutesFromElements, useRouteError } from 'react-router-dom'
import { DefaultErrorFallback } from './components/DefaultErrorFallback/DefaultErrorFallback'
import { ErrorPage } from './components/ErrorPage/ErrorPage'
+const LoginRedirectPage = lazy(() => import('./components/LoginRedirectPage/LoginRedirectPage'))
+
export const router = createRoutesFromElements(
{
@@ -19,42 +21,27 @@ export const router = createRoutesFromElements(
captureException(error)
}, [error])
+ let header = 'Something went wrong'
+ let para1 =
+ 'Please try refreshing the page. Still having trouble? Let us know at hello@tldraw.com.'
if (error instanceof TLRemoteSyncError) {
switch (error.reason) {
case TLSyncErrorCloseEventReason.NOT_FOUND: {
- return (
-
- )
+ header = 'Not found'
+ para1 = 'The file you are looking for does not exist.'
+ break
}
case TLSyncErrorCloseEventReason.NOT_AUTHENTICATED: {
return (
-
+
+
+
)
}
case TLSyncErrorCloseEventReason.FORBIDDEN: {
- return (
-
- {'Back to tldraw.'}
-
- }
- />
- )
+ header = 'Forbidden'
+ para1 = 'You are forbidden to view this file.'
+ break
}
}
}
@@ -62,9 +49,8 @@ export const router = createRoutesFromElements(
return (
)
diff --git a/apps/dotcom/sync-worker/src/TLDrawDurableObject.ts b/apps/dotcom/sync-worker/src/TLDrawDurableObject.ts
index 4b58a8a0c8f4..e9004778ac2e 100644
--- a/apps/dotcom/sync-worker/src/TLDrawDurableObject.ts
+++ b/apps/dotcom/sync-worker/src/TLDrawDurableObject.ts
@@ -333,6 +333,9 @@ export class TLDrawDurableObject extends DurableObject {
const ownerId = await this.getOwnerId()
if (ownerId) {
+ if (!auth) {
+ return closeSocket(TLSyncErrorCloseEventReason.NOT_AUTHENTICATED)
+ }
if (ownerId !== TldrawAppUserRecordType.createId(auth?.userId)) {
const ownerDurableObject = this.env.TLAPP_DO.get(this.env.TLAPP_DO.idFromName(APP_ID))
const shareType = await ownerDurableObject.getFileShareType(
diff --git a/packages/sync/src/useSync.ts b/packages/sync/src/useSync.ts
index c321c338c964..356314ca9838 100644
--- a/packages/sync/src/useSync.ts
+++ b/packages/sync/src/useSync.ts
@@ -162,7 +162,7 @@ export function useSync(opts: UseSyncOptions & TLStoreSchemaOptions): RemoteTLSt
track?.(MULTIPLAYER_EVENT_NAME, { name: 'room-not-found', roomId })
break
case TLSyncErrorCloseEventReason.FORBIDDEN:
- track?.(MULTIPLAYER_EVENT_NAME, { name: 'not-authorized', roomId })
+ track?.(MULTIPLAYER_EVENT_NAME, { name: 'forbidden', roomId })
break
case TLSyncErrorCloseEventReason.NOT_AUTHENTICATED:
track?.(MULTIPLAYER_EVENT_NAME, { name: 'not-authenticated', roomId })