-
Notifications
You must be signed in to change notification settings - Fork 126
/
Copy pathtoken-exchange.ts
76 lines (65 loc) · 2.27 KB
/
token-exchange.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
import {throwFailedRequest} from '../../clients/common';
import {decodeSessionToken} from '../../session/decode-session-token';
import {sanitizeShop} from '../../utils/shop-validator';
import {ConfigInterface} from '../../base-types';
import {Session} from '../../session/session';
import {DataType} from '../../clients/types';
import {fetchRequestFactory} from '../../utils/fetch-request';
import {createSession} from './create-session';
import {AccessTokenResponse} from './types';
export enum RequestedTokenType {
OnlineAccessToken = 'urn:shopify:params:oauth:token-type:online-access-token',
OfflineAccessToken = 'urn:shopify:params:oauth:token-type:offline-access-token',
}
const TokenExchangeGrantType =
'urn:ietf:params:oauth:grant-type:token-exchange';
const IdTokenType = 'urn:ietf:params:oauth:token-type:id_token';
export interface TokenExchangeParams {
shop: string;
sessionToken: string;
requestedTokenType: RequestedTokenType;
}
export type TokenExchange = (
params: TokenExchangeParams,
) => Promise<{session: Session}>;
export function tokenExchange(config: ConfigInterface): TokenExchange {
return async ({
shop,
sessionToken,
requestedTokenType,
}: TokenExchangeParams) => {
await decodeSessionToken(config)(sessionToken);
const body = {
client_id: config.apiKey,
client_secret: config.apiSecretKey,
grant_type: TokenExchangeGrantType,
subject_token: sessionToken,
subject_token_type: IdTokenType,
requested_token_type: requestedTokenType,
};
const cleanShop = sanitizeShop(config)(shop, true)!;
const postResponse = await fetchRequestFactory(config)(
`https://${cleanShop}/admin/oauth/access_token`,
{
method: 'POST',
body: JSON.stringify(body),
headers: {
'Content-Type': DataType.JSON,
Accept: DataType.JSON,
},
},
);
if (!postResponse.ok) {
throwFailedRequest(await postResponse.json(), false, postResponse);
}
return {
session: createSession({
accessTokenResponse: await postResponse.json<AccessTokenResponse>(),
shop: cleanShop,
// We need to keep this as an empty string as our template DB schemas have this required
state: '',
config,
}),
};
};
}