Skip to content

Commit 9c1ad58

Browse files
authored
feat!: use hosted login for standalone apps (#386)
* feat!: use hosted login for standalone apps * feat: set the timeout to 12 hours for local and dashboard
1 parent 32621b3 commit 9c1ad58

27 files changed

+156
-872
lines changed

apps/kitchensink-react/src/ProjectAuthentication/ProjectAuthHome.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import {AuthBoundary} from '@sanity/sdk-react'
2-
import {Card, Flex, Text} from '@sanity/ui'
1+
import {AuthBoundary, useLogOut} from '@sanity/sdk-react'
2+
import {Button, Card, Flex, Text} from '@sanity/ui'
33
import {type JSX} from 'react'
44
import {Link} from 'react-router'
55

@@ -10,6 +10,7 @@ export function ProjectAuthHome({
1010
}: {
1111
routes: {path: string; element: JSX.Element}[]
1212
}): JSX.Element {
13+
const logout = useLogOut()
1314
return (
1415
<PageLayout title="Authenticated" subtitle="Explore authentication examples and components">
1516
<AuthBoundary>
@@ -25,6 +26,9 @@ export function ProjectAuthHome({
2526
</Card>
2627
</Link>
2728
))}
29+
<Button mode="ghost" onClick={() => logout()}>
30+
Logout
31+
</Button>
2832
</Flex>
2933
</AuthBoundary>
3034
</PageLayout>

packages/core/src/_exports/index.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,12 @@ export {
1313
getAuthState,
1414
getCurrentUserState,
1515
getDashboardOrganizationId,
16-
getLoginUrlsState,
16+
getLoginUrlState,
1717
getTokenState,
1818
type LoggedInAuthState,
1919
type LoggedOutAuthState,
2020
type LoggingInAuthState,
2121
} from '../auth/authStore'
22-
export {fetchLoginUrls} from '../auth/fetchLoginUrls'
2322
export {handleAuthCallback} from '../auth/handleAuthCallback'
2423
export {logout} from '../auth/logout'
2524
export type {ClientStoreState as ClientState} from '../client/clientStore'

packages/core/src/auth/authStore.test.ts

Lines changed: 6 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,9 @@ import {
1010
getAuthState,
1111
getCurrentUserState,
1212
getDashboardOrganizationId,
13-
getLoginUrlsState,
13+
getLoginUrlState,
1414
getTokenState,
1515
} from './authStore'
16-
import {fetchLoginUrls} from './fetchLoginUrls'
1716
import {handleAuthCallback} from './handleAuthCallback'
1817
import {subscribeToStateAndFetchCurrentUser} from './subscribeToStateAndFetchCurrentUser'
1918
import {subscribeToStorageEventsAndSetToken} from './subscribeToStorageEventsAndSetToken'
@@ -297,38 +296,13 @@ describe('authStore', () => {
297296
instance?.dispose()
298297
})
299298

300-
it('returns the cached auth providers if present', async () => {
301-
instance = createSanityInstance({
302-
projectId: 'p',
303-
dataset: 'd',
304-
auth: {
305-
providers: [{name: 'test', title: 'Test', url: 'https://example.com'}],
306-
clientFactory: vi.fn().mockReturnValue({
307-
request: vi.fn().mockResolvedValue({providers: []}),
308-
}),
309-
},
310-
})
311-
312-
await fetchLoginUrls(instance)
313-
314-
const {getCurrent} = getLoginUrlsState(instance)
315-
expect(getCurrent()).toEqual([
316-
{
317-
name: 'test',
318-
title: 'Test',
319-
url: 'https://example.com/?origin=http%3A%2F%2Flocalhost%2F&withSid=true&type=stampedToken',
320-
},
321-
])
322-
323-
// pureness check
324-
expect(getCurrent()).toBe(getCurrent())
325-
})
326-
327-
it('returns nulls otherwise', () => {
299+
it('returns the default login url', () => {
328300
instance = createSanityInstance({projectId: 'p', dataset: 'd'})
329301

330-
const loginUrlsState = getLoginUrlsState(instance)
331-
expect(loginUrlsState.getCurrent()).toBe(null)
302+
const loginUrlState = getLoginUrlState(instance)
303+
expect(loginUrlState.getCurrent()).toBe(
304+
'https://www.sanity.io/login?origin=http%3A%2F%2Flocalhost&type=stampedToken&withSid=true',
305+
)
332306
})
333307
})
334308

packages/core/src/auth/authStore.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ export interface AuthStoreState {
7373
storageKey: string
7474
storageArea: Storage | undefined
7575
apiHost: string | undefined
76+
loginUrl: string
7677
callbackUrl: string | undefined
7778
providedToken: string | undefined
7879
}
@@ -94,6 +95,20 @@ export const authStore = defineStore<AuthStoreState>({
9495

9596
const storageKey = `__sanity_auth_token`
9697

98+
// This login URL will only be used for local development
99+
let loginDomain = 'https://www.sanity.io'
100+
try {
101+
if (apiHost && new URL(apiHost).hostname.endsWith('.sanity.work')) {
102+
loginDomain = 'https://www.sanity.work'
103+
}
104+
} catch {
105+
/* empty */
106+
}
107+
const loginUrl = new URL('/login', loginDomain)
108+
loginUrl.searchParams.set('origin', initialLocationHref)
109+
loginUrl.searchParams.set('type', 'stampedToken') // Token must be stamped to have an sid passed back
110+
loginUrl.searchParams.set('withSid', 'true')
111+
97112
let authState: AuthState
98113

99114
const token = getTokenFromStorage(storageArea, storageKey)
@@ -112,6 +127,7 @@ export const authStore = defineStore<AuthStoreState>({
112127
authState,
113128
options: {
114129
apiHost,
130+
loginUrl: loginUrl.toString(),
115131
callbackUrl,
116132
customProviders,
117133
providedToken,
@@ -166,9 +182,9 @@ export const getTokenState = bindActionGlobally(
166182
/**
167183
* @public
168184
*/
169-
export const getLoginUrlsState = bindActionGlobally(
185+
export const getLoginUrlState = bindActionGlobally(
170186
authStore,
171-
createStateSourceAction(({state: {providers}}) => providers ?? null),
187+
createStateSourceAction(({state: {options}}) => options.loginUrl),
172188
)
173189

174190
/**

packages/core/src/auth/fetchLoginUrls.test.ts

Lines changed: 0 additions & 167 deletions
This file was deleted.

packages/core/src/auth/fetchLoginUrls.ts

Lines changed: 0 additions & 72 deletions
This file was deleted.

0 commit comments

Comments
 (0)