Skip to content

Commit 7f09479

Browse files
attempt to fetch mock user from identity endpoint
1 parent e27ed44 commit 7f09479

File tree

3 files changed

+124
-1
lines changed

3 files changed

+124
-1
lines changed

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
import {IdentityToken, Session, Sessions} from './session/schema.js'
1313
import * as sessionStore from './session/store.js'
1414
import {pollForDeviceAuthorization, requestDeviceAuthorization} from './session/device-authorization.js'
15+
import {shouldUseMockAuth, fetchMockUser, buildMockSession} from './session/mock-auth.js'
1516
import {isThemeAccessSession} from './api/rest.js'
1617
import {getCurrentSessionId, setCurrentSessionId} from './conf-store.js'
1718
import {UserEmailQueryString, UserEmailQuery} from './api/graphql/business-platform-destinations/user-email.js'
@@ -197,6 +198,7 @@ export async function ensureAuthenticated(
197198
{forceRefresh = false, noPrompt = false, forceNewSession = false}: EnsureAuthenticatedAdditionalOptions = {},
198199
): Promise<OAuthSession> {
199200
const fqdn = await identityFqdn()
201+
// debugger
200202

201203
const previousStoreFqdn = applications.adminApi?.storeFqdn
202204
if (previousStoreFqdn) {
@@ -301,6 +303,15 @@ async function executeCompleteFlow(applications: OAuthApplications): Promise<Ses
301303
scopes.push('employee')
302304
}
303305

306+
// debugger
307+
if (shouldUseMockAuth()) {
308+
outputDebug(outputContent`Using mock authentication...`)
309+
const mockUser = await fetchMockUser(scopes)
310+
const session = buildMockSession(mockUser, scopes)
311+
outputCompleted(`Logged in with mock user: ${mockUser.userinfo.email}`)
312+
return session
313+
}
314+
304315
let identityToken: IdentityToken
305316
const identityTokenInformation = getIdentityTokenInformation()
306317
if (identityTokenInformation) {
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
import {IdentityToken, Session} from './schema.js'
2+
import {shopifyFetch} from '../../../public/node/http.js'
3+
import {outputDebug, outputContent, outputToken} from '../../../public/node/output.js'
4+
import {isLocalEnvironment} from '../context/service.js'
5+
import {assertConnectable} from '../../../public/node/vendor/dev_server/network/index.js'
6+
import {developerDashboardFqdn} from '../../../public/node/context/fqdn.js'
7+
8+
interface MockUserResponse {
9+
uuid: string
10+
expires_at: string
11+
id_token: string
12+
access_token: string
13+
refresh_token: string
14+
last_login: string
15+
scope: string
16+
userinfo: {
17+
email: string
18+
email_verified: boolean
19+
given_name: string
20+
family_name: string
21+
name: string
22+
picture: string
23+
zoneinfo: string
24+
locale: string
25+
permissions: string[]
26+
okta_id: string | null
27+
updated_at: string
28+
created_at: string
29+
}
30+
}
31+
32+
export function shouldUseMockAuth(): boolean {
33+
if (!isLocalEnvironment()) {
34+
return false
35+
}
36+
37+
try {
38+
assertConnectable({
39+
projectName: 'identity',
40+
addr: '127.0.0.1',
41+
port: 8080,
42+
timeout: 100,
43+
})
44+
return false
45+
} catch (e) {
46+
outputDebug(outputContent`Identity service is not running. Using mock authentication.`)
47+
throw e
48+
return true
49+
}
50+
}
51+
52+
export async function fetchMockUser(scopes: string[]): Promise<MockUserResponse> {
53+
const devDashboardFqdn = await developerDashboardFqdn()
54+
const scopeParam = scopes.join(' ')
55+
const nonce = Math.random().toString(36).substring(2)
56+
const state = Math.random().toString(36).substring(2)
57+
58+
const params = new URLSearchParams({
59+
'config-key': 'cli',
60+
scope: scopeParam,
61+
nonce,
62+
state,
63+
'created-at': Date.now().toString(),
64+
})
65+
66+
const url = `https://${devDashboardFqdn}/identity/test-login?${params.toString()}`
67+
68+
outputDebug(outputContent`Fetching mock user from: ${url}`)
69+
70+
const response = await shopifyFetch(url, {
71+
method: 'POST',
72+
headers: {
73+
'Content-Type': 'application/x-www-form-urlencoded',
74+
Accept: 'application/json',
75+
},
76+
})
77+
78+
if (!response.ok) {
79+
const text = await response.text()
80+
outputDebug(outputContent`Failed response: ${text.substring(0, 500)}`)
81+
throw new Error(`Failed to fetch mock user: ${response.status} ${response.statusText}`)
82+
}
83+
84+
const data = (await response.json()) as MockUserResponse
85+
outputDebug(outputContent`Mock user fetched: ${outputToken.json(data)}`)
86+
87+
return data
88+
}
89+
90+
export function buildMockIdentityToken(mockUser: MockUserResponse, scopes: string[]): IdentityToken {
91+
const expiresAt = new Date(mockUser.expires_at)
92+
93+
return {
94+
accessToken: mockUser.access_token,
95+
refreshToken: mockUser.refresh_token,
96+
expiresAt,
97+
scopes,
98+
userId: mockUser.uuid,
99+
}
100+
}
101+
102+
export function buildMockSession(mockUser: MockUserResponse, scopes: string[]): Session {
103+
const identityToken = buildMockIdentityToken(mockUser, scopes)
104+
105+
return {
106+
identity: {
107+
...identityToken,
108+
alias: mockUser.userinfo.email,
109+
},
110+
applications: {},
111+
}
112+
}

packages/cli-kit/src/public/node/vendor/dev_server/network/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ let checkPort: ReturnType<typeof getCheckPortHelper>
1818

1919
export function assertConnectable(options: ConnectionArguments): void {
2020
checkPort ||= getCheckPortHelper()
21-
debugger
21+
// debugger
2222

2323
const {port, addr, timeout = DEFAULT_CONNECT_TIMEOUT} = options
2424
try {

0 commit comments

Comments
 (0)