Skip to content

Commit 9d46d44

Browse files
authored
Revert "Simplify authentication flow"
1 parent 91fb70d commit 9d46d44

6 files changed

Lines changed: 467 additions & 100 deletions

File tree

packages/cli-kit/src/private/node/session.test.ts

Lines changed: 81 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,17 @@ import {
77
setLastSeenAuthMethod,
88
setLastSeenUserIdAfterAuth,
99
} from './session.js'
10-
import {exchangeCustomPartnerToken, refreshAccessToken, InvalidGrantError} from './session/exchange.js'
10+
import {
11+
exchangeAccessForApplicationTokens,
12+
exchangeCustomPartnerToken,
13+
refreshAccessToken,
14+
InvalidGrantError,
15+
} from './session/exchange.js'
1116
import {allDefaultScopes} from './session/scopes.js'
1217
import {store as storeSessions, fetch as fetchSessions, remove as secureRemove} from './session/store.js'
13-
import {IdentityToken, Sessions} from './session/schema.js'
18+
import {ApplicationToken, IdentityToken, Sessions} from './session/schema.js'
1419
import {validateSession} from './session/validate.js'
20+
import {applicationId} from './session/identity.js'
1521
import {pollForDeviceAuthorization, requestDeviceAuthorization} from './session/device-authorization.js'
1622
import {getCurrentSessionId} from './conf-store.js'
1723
import * as fqdnModule from '../../public/node/context/fqdn.js'
@@ -44,15 +50,54 @@ const validIdentityToken: IdentityToken = {
4450
}
4551

4652
const validTokens: OAuthSession = {
47-
admin: {token: 'access_token', storeFqdn: 'mystore.myshopify.com'},
48-
storefront: 'access_token',
49-
partners: 'access_token',
53+
admin: {token: 'admin_token', storeFqdn: 'mystore.myshopify.com'},
54+
storefront: 'storefront_token',
55+
partners: 'partners_token',
5056
userId,
5157
}
5258

59+
const appTokens: Record<string, ApplicationToken> = {
60+
// Admin APIs includes domain in the key
61+
'mystore.myshopify.com-admin': {
62+
accessToken: 'admin_token',
63+
expiresAt: futureDate,
64+
scopes: ['scope', 'scope2'],
65+
},
66+
'storefront-renderer': {
67+
accessToken: 'storefront_token',
68+
expiresAt: futureDate,
69+
scopes: ['scope1'],
70+
},
71+
partners: {
72+
accessToken: 'partners_token',
73+
expiresAt: futureDate,
74+
scopes: ['scope2'],
75+
},
76+
'business-platform': {
77+
accessToken: 'business_platform_token',
78+
expiresAt: futureDate,
79+
scopes: ['scope3'],
80+
},
81+
}
82+
83+
const partnersToken: ApplicationToken = {
84+
accessToken: 'custom_partners_token',
85+
expiresAt: futureDate,
86+
scopes: ['scope2'],
87+
}
88+
5389
const fqdn = 'fqdn.com'
5490

5591
const validSessions: Sessions = {
92+
[fqdn]: {
93+
[userId]: {
94+
identity: validIdentityToken,
95+
applications: appTokens,
96+
},
97+
},
98+
}
99+
100+
const invalidSessions: Sessions = {
56101
[fqdn]: {
57102
[userId]: {
58103
identity: validIdentityToken,
@@ -62,6 +107,7 @@ const validSessions: Sessions = {
62107
}
63108

64109
vi.mock('../../public/node/context/local.js')
110+
vi.mock('./session/identity')
65111
vi.mock('./session/authorize')
66112
vi.mock('./session/exchange')
67113
vi.mock('./session/scopes')
@@ -77,9 +123,11 @@ vi.mock('../../public/node/system.js')
77123

78124
beforeEach(() => {
79125
vi.spyOn(fqdnModule, 'identityFqdn').mockResolvedValue(fqdn)
126+
vi.mocked(exchangeAccessForApplicationTokens).mockResolvedValue(appTokens)
80127
vi.mocked(refreshAccessToken).mockResolvedValue(validIdentityToken)
128+
vi.mocked(applicationId).mockImplementation((app) => app)
81129
vi.mocked(exchangeCustomPartnerToken).mockResolvedValue({
82-
accessToken: 'custom_partners_token',
130+
accessToken: partnersToken.accessToken,
83131
userId: validIdentityToken.userId,
84132
})
85133
vi.mocked(partnersRequest).mockResolvedValue(undefined)
@@ -114,6 +162,7 @@ describe('ensureAuthenticated when previous session is invalid', () => {
114162
const got = await ensureAuthenticated(defaultApplications)
115163

116164
// Then
165+
expect(exchangeAccessForApplicationTokens).toBeCalled()
117166
expect(refreshAccessToken).not.toBeCalled()
118167
expect(businessPlatformRequest).toHaveBeenCalled()
119168
expect(storeSessions).toHaveBeenCalledOnce()
@@ -153,16 +202,16 @@ The CLI is currently unable to prompt for reauthentication.`,
153202
test('executes complete auth flow if session is for a different fqdn', async () => {
154203
// Given
155204
vi.mocked(validateSession).mockResolvedValueOnce('needs_full_auth')
156-
vi.mocked(fetchSessions).mockResolvedValue(validSessions)
205+
vi.mocked(fetchSessions).mockResolvedValue(invalidSessions)
157206
const expectedSessions = {
158-
...validSessions,
207+
...invalidSessions,
159208
[fqdn]: {
160209
[userId]: {
161210
identity: {
162211
...validIdentityToken,
163212
alias: 'user@example.com',
164213
},
165-
applications: {},
214+
applications: appTokens,
166215
},
167216
},
168217
}
@@ -171,7 +220,7 @@ The CLI is currently unable to prompt for reauthentication.`,
171220
const got = await ensureAuthenticated(defaultApplications)
172221

173222
// Then
174-
223+
expect(exchangeAccessForApplicationTokens).toBeCalled()
175224
expect(refreshAccessToken).not.toBeCalled()
176225
expect(storeSessions).toBeCalledWith(expectedSessions)
177226
expect(got).toEqual(validTokens)
@@ -190,7 +239,7 @@ The CLI is currently unable to prompt for reauthentication.`,
190239
const got = await ensureAuthenticated(defaultApplications)
191240

192241
// Then
193-
242+
expect(exchangeAccessForApplicationTokens).toBeCalled()
194243
expect(businessPlatformRequest).toHaveBeenCalled()
195244
expect(storeSessions).toHaveBeenCalledOnce()
196245

@@ -201,20 +250,26 @@ The CLI is currently unable to prompt for reauthentication.`,
201250
expect(got).toEqual(validTokens)
202251
})
203252

204-
test('uses identity token to fetch email during full auth flow', async () => {
253+
test('falls back to userId when no business platform token available', async () => {
205254
// Given
206255
vi.mocked(validateSession).mockResolvedValueOnce('needs_full_auth')
207256
vi.mocked(fetchSessions).mockResolvedValue(undefined)
257+
const appTokensWithoutBusinessPlatform = {
258+
'mystore.myshopify.com-admin': appTokens['mystore.myshopify.com-admin']!,
259+
'storefront-renderer': appTokens['storefront-renderer']!,
260+
partners: appTokens.partners!,
261+
}
262+
vi.mocked(exchangeAccessForApplicationTokens).mockResolvedValueOnce(appTokensWithoutBusinessPlatform)
208263

209264
// When
210265
const got = await ensureAuthenticated(defaultApplications)
211266

212267
// Then
213-
expect(businessPlatformRequest).toHaveBeenCalledWith(expect.any(String), 'access_token')
268+
expect(businessPlatformRequest).not.toHaveBeenCalled()
214269

215-
// Verify the session was stored with email as alias
270+
// Verify the session was stored with userId as alias (fallback)
216271
const storedSession = vi.mocked(storeSessions).mock.calls[0]![0]
217-
expect(storedSession[fqdn]![userId]!.identity.alias).toBe('user@example.com')
272+
expect(storedSession[fqdn]![userId]!.identity.alias).toBe(userId)
218273
})
219274

220275
test('executes complete auth flow if requesting additional scopes', async () => {
@@ -226,7 +281,7 @@ The CLI is currently unable to prompt for reauthentication.`,
226281
const got = await ensureAuthenticated(defaultApplications)
227282

228283
// Then
229-
284+
expect(exchangeAccessForApplicationTokens).toBeCalled()
230285
expect(refreshAccessToken).not.toBeCalled()
231286
expect(businessPlatformRequest).toHaveBeenCalled()
232287
expect(storeSessions).toHaveBeenCalledOnce()
@@ -252,7 +307,7 @@ describe('when existing session is valid', () => {
252307
const got = await ensureAuthenticated(defaultApplications)
253308

254309
// Then
255-
310+
expect(exchangeAccessForApplicationTokens).not.toBeCalled()
256311
expect(refreshAccessToken).not.toBeCalled()
257312
expect(got).toEqual(validTokens)
258313
await expect(getLastSeenUserIdAfterAuth()).resolves.toBe('1234-5678')
@@ -265,18 +320,13 @@ describe('when existing session is valid', () => {
265320
vi.mocked(validateSession).mockResolvedValueOnce('ok')
266321
vi.mocked(fetchSessions).mockResolvedValue(validSessions)
267322
vi.mocked(getPartnersToken).mockReturnValue('custom_cli_token')
268-
const expected = {
269-
admin: {token: 'access_token', storeFqdn: 'mystore.myshopify.com'},
270-
storefront: 'access_token',
271-
partners: 'custom_partners_token',
272-
userId,
273-
}
323+
const expected = {...validTokens, partners: 'custom_partners_token'}
274324

275325
// When
276326
const got = await ensureAuthenticated(defaultApplications)
277327

278328
// Then
279-
329+
expect(exchangeAccessForApplicationTokens).not.toBeCalled()
280330
expect(refreshAccessToken).not.toBeCalled()
281331
expect(got).toEqual(expected)
282332
await expect(getLastSeenUserIdAfterAuth()).resolves.toBe('1234-5678')
@@ -294,16 +344,8 @@ describe('when existing session is valid', () => {
294344

295345
// Then
296346
expect(refreshAccessToken).toBeCalled()
297-
298-
const expectedSessions = {
299-
[fqdn]: {
300-
[userId]: {
301-
identity: validIdentityToken,
302-
applications: {},
303-
},
304-
},
305-
}
306-
expect(storeSessions).toBeCalledWith(expectedSessions)
347+
expect(exchangeAccessForApplicationTokens).toBeCalled()
348+
expect(storeSessions).toBeCalledWith(validSessions)
307349
expect(got).toEqual(validTokens)
308350
await expect(getLastSeenUserIdAfterAuth()).resolves.toBe('1234-5678')
309351
await expect(getLastSeenAuthMethod()).resolves.toEqual('device_auth')
@@ -322,16 +364,8 @@ describe('when existing session is expired', () => {
322364

323365
// Then
324366
expect(refreshAccessToken).toBeCalled()
325-
326-
const expectedSessions = {
327-
[fqdn]: {
328-
[userId]: {
329-
identity: validIdentityToken,
330-
applications: {},
331-
},
332-
},
333-
}
334-
expect(storeSessions).toBeCalledWith(expectedSessions)
367+
expect(exchangeAccessForApplicationTokens).toBeCalled()
368+
expect(storeSessions).toBeCalledWith(validSessions)
335369
expect(got).toEqual(validTokens)
336370
await expect(getLastSeenUserIdAfterAuth()).resolves.toBe('1234-5678')
337371
await expect(getLastSeenAuthMethod()).resolves.toEqual('device_auth')
@@ -351,7 +385,7 @@ describe('when existing session is expired', () => {
351385

352386
// Then
353387
expect(refreshAccessToken).toBeCalled()
354-
388+
expect(exchangeAccessForApplicationTokens).toBeCalled()
355389
expect(businessPlatformRequest).toHaveBeenCalled()
356390
expect(storeSessions).toHaveBeenCalledOnce()
357391

@@ -610,15 +644,7 @@ describe('ensureAuthenticated email fetch functionality', () => {
610644
const got = await ensureAuthenticated(defaultApplications)
611645

612646
// Then
613-
const expectedSessions = {
614-
[fqdn]: {
615-
[userId]: {
616-
identity: validIdentityToken,
617-
applications: {},
618-
},
619-
},
620-
}
621-
expect(storeSessions).toBeCalledWith(expectedSessions)
647+
expect(storeSessions).toBeCalledWith(validSessions)
622648
expect(got).toEqual(validTokens)
623649
})
624650

@@ -633,15 +659,7 @@ describe('ensureAuthenticated email fetch functionality', () => {
633659
// Then
634660
// The email fetch is not called during refresh - the session keeps its existing alias
635661
expect(businessPlatformRequest).not.toHaveBeenCalled()
636-
const expectedSessions = {
637-
[fqdn]: {
638-
[userId]: {
639-
identity: validIdentityToken,
640-
applications: {},
641-
},
642-
},
643-
}
644-
expect(storeSessions).toBeCalledWith(expectedSessions)
662+
expect(storeSessions).toBeCalledWith(validSessions)
645663
expect(got).toEqual(validTokens)
646664
})
647665

0 commit comments

Comments
 (0)