Skip to content

Commit 4871ee8

Browse files
remove shared identity code that is now in client
1 parent aa6704a commit 4871ee8

File tree

3 files changed

+3
-170
lines changed

3 files changed

+3
-170
lines changed

packages/cli-kit/src/private/node/clients/identity/identity-service-client.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ export class IdentityServiceClient extends IdentityClient {
4949
return err({error: payload.error, store: params.store})
5050
}
5151

52+
/**
53+
* Given an expired access token, refresh it to get a new one.
54+
*/
5255
async refreshAccessToken(currentToken: IdentityToken): Promise<IdentityToken> {
5356
const clientId = this.clientId()
5457
const params = {

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

Lines changed: 0 additions & 149 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,3 @@
1-
import {exchangeDeviceCodeForAccessToken} from './exchange.js'
2-
import {IdentityToken} from './schema.js'
3-
import {identityFqdn} from '../../../public/node/context/fqdn.js'
4-
import {shopifyFetch} from '../../../public/node/http.js'
5-
import {outputContent, outputDebug, outputInfo, outputToken} from '../../../public/node/output.js'
6-
import {AbortError, BugError} from '../../../public/node/error.js'
7-
import {isCloudEnvironment} from '../../../public/node/context/local.js'
8-
import {isCI, openURL} from '../../../public/node/system.js'
9-
import {isTTY, keypress} from '../../../public/node/ui.js'
10-
import {getIdentityClient} from '../clients/identity/instance.js'
111
import {Response} from 'node-fetch'
122

133
export interface DeviceAuthorizationResponse {
@@ -19,145 +9,6 @@ export interface DeviceAuthorizationResponse {
199
interval?: number
2010
}
2111

22-
/**
23-
* Initiate a device authorization flow.
24-
* This will return a DeviceAuthorizationResponse containing the URL where user
25-
* should go to authorize the device without the need of a callback to the CLI.
26-
*
27-
* Also returns a `deviceCode` used for polling the token endpoint in the next step.
28-
*
29-
* @param scopes - The scopes to request
30-
* @returns An object with the device authorization response.
31-
*/
32-
export async function requestDeviceAuthorization(scopes: string[]): Promise<DeviceAuthorizationResponse> {
33-
const fqdn = await identityFqdn()
34-
const identityClientId = getIdentityClient().clientId()
35-
const queryParams = {client_id: identityClientId, scope: scopes.join(' ')}
36-
const url = `https://${fqdn}/oauth/device_authorization`
37-
38-
const response = await shopifyFetch(url, {
39-
method: 'POST',
40-
headers: {'Content-type': 'application/x-www-form-urlencoded'},
41-
body: convertRequestToParams(queryParams),
42-
})
43-
44-
// First read the response body as text so we have it for debugging
45-
let responseText: string
46-
try {
47-
responseText = await response.text()
48-
} catch (error) {
49-
throw new BugError(
50-
`Failed to read response from authorization service (HTTP ${response.status}). Network or streaming error occurred.`,
51-
'Check your network connection and try again.',
52-
)
53-
}
54-
55-
// Now try to parse the text as JSON
56-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
57-
let jsonResult: any
58-
try {
59-
jsonResult = JSON.parse(responseText)
60-
} catch {
61-
// JSON.parse failed, handle the parsing error
62-
const errorMessage = buildAuthorizationParseErrorMessage(response, responseText)
63-
throw new BugError(errorMessage)
64-
}
65-
66-
outputDebug(outputContent`Received device authorization code: ${outputToken.json(jsonResult)}`)
67-
if (!jsonResult.device_code || !jsonResult.verification_uri_complete) {
68-
throw new BugError('Failed to start authorization process')
69-
}
70-
71-
outputInfo('\nTo run this command, log in to Shopify.')
72-
73-
if (isCI()) {
74-
throw new AbortError(
75-
'Authorization is required to continue, but the current environment does not support interactive prompts.',
76-
'To resolve this, specify credentials in your environment, or run the command in an interactive environment such as your local terminal.',
77-
)
78-
}
79-
80-
outputInfo(outputContent`User verification code: ${jsonResult.user_code}`)
81-
const linkToken = outputToken.link(jsonResult.verification_uri_complete)
82-
83-
const cloudMessage = () => {
84-
outputInfo(outputContent`👉 Open this link to start the auth process: ${linkToken}`)
85-
}
86-
87-
if (isCloudEnvironment() || !isTTY()) {
88-
cloudMessage()
89-
} else {
90-
outputInfo('👉 Press any key to open the login page on your browser')
91-
await keypress()
92-
const opened = await openURL(jsonResult.verification_uri_complete)
93-
if (opened) {
94-
outputInfo(outputContent`Opened link to start the auth process: ${linkToken}`)
95-
} else {
96-
cloudMessage()
97-
}
98-
}
99-
100-
return {
101-
deviceCode: jsonResult.device_code,
102-
userCode: jsonResult.user_code,
103-
verificationUri: jsonResult.verification_uri,
104-
expiresIn: jsonResult.expires_in,
105-
verificationUriComplete: jsonResult.verification_uri_complete,
106-
interval: jsonResult.interval,
107-
}
108-
}
109-
110-
/**
111-
* Poll the Oauth token endpoint with the device code obtained from a DeviceAuthorizationResponse.
112-
* The endpoint will return `authorization_pending` until the user completes the auth flow in the browser.
113-
* Once the user completes the auth flow, the endpoint will return the identity token.
114-
*
115-
* Timeout for the polling is defined by the server and is around 600 seconds.
116-
*
117-
* @param code - The device code obtained after starting a device identity flow
118-
* @param interval - The interval to poll the token endpoint
119-
* @returns The identity token
120-
*/
121-
export async function pollForDeviceAuthorization(code: string, interval = 5): Promise<IdentityToken> {
122-
let currentIntervalInSeconds = interval
123-
124-
return new Promise<IdentityToken>((resolve, reject) => {
125-
const onPoll = async () => {
126-
const result = await exchangeDeviceCodeForAccessToken(code)
127-
if (!result.isErr()) {
128-
resolve(result.value)
129-
return
130-
}
131-
132-
const error = result.error ?? 'unknown_failure'
133-
134-
outputDebug(outputContent`Polling for device authorization... status: ${error}`)
135-
switch (error) {
136-
case 'authorization_pending': {
137-
startPolling()
138-
return
139-
}
140-
case 'slow_down':
141-
currentIntervalInSeconds += 5
142-
startPolling()
143-
return
144-
case 'access_denied':
145-
case 'expired_token':
146-
case 'unknown_failure': {
147-
reject(new Error(`Device authorization failed: ${error}`))
148-
}
149-
}
150-
}
151-
152-
const startPolling = () => {
153-
// eslint-disable-next-line @typescript-eslint/no-misused-promises
154-
setTimeout(onPoll, currentIntervalInSeconds * 1000)
155-
}
156-
157-
startPolling()
158-
})
159-
}
160-
16112
export function convertRequestToParams(queryParams: {client_id: string; scope: string}): string {
16213
return Object.entries(queryParams)
16314
.map(([key, value]) => value && `${key}=${value}`)

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

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@ import {ApplicationToken, IdentityToken} from './schema.js'
22
import {applicationId} from './identity.js'
33
import {tokenExchangeScopes} from './scopes.js'
44
import {API} from '../api.js'
5-
import {identityFqdn} from '../../../public/node/context/fqdn.js'
6-
import {shopifyFetch} from '../../../public/node/http.js'
75
import {err, ok, Result} from '../../../public/node/result.js'
86
import {AbortError, BugError, ExtendableError} from '../../../public/node/error.js'
97
import {setLastSeenAuthMethod, setLastSeenUserIdAfterAuth} from '../session.js'
@@ -53,9 +51,6 @@ export async function exchangeAccessForApplicationTokens(
5351
}
5452
}
5553

56-
/**
57-
* Given an expired access token, refresh it to get a new one.
58-
*/
5954
export async function refreshAccessToken(currentToken: IdentityToken): Promise<IdentityToken> {
6055
const clientId = getIdentityClient().clientId()
6156
const params = {
@@ -222,22 +217,6 @@ export function tokenRequestErrorHandler({error, store}: {error: string; store?:
222217
return new AbortError(error)
223218
}
224219

225-
async function _tokenRequest(params: {
226-
[key: string]: string
227-
}): Promise<Result<TokenRequestResult, {error: string; store?: string}>> {
228-
const fqdn = await identityFqdn()
229-
const url = new URL(`https://${fqdn}/oauth/token`)
230-
url.search = new URLSearchParams(Object.entries(params)).toString()
231-
232-
const res = await shopifyFetch(url.href, {method: 'POST'})
233-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
234-
const payload: any = await res.json()
235-
236-
if (res.ok) return ok(payload)
237-
238-
return err({error: payload.error, store: params.store})
239-
}
240-
241220
export function buildIdentityToken(
242221
result: TokenRequestResult,
243222
existingUserId?: string,

0 commit comments

Comments
 (0)