-
Notifications
You must be signed in to change notification settings - Fork 22
Expand file tree
/
Copy pathAuthorization.ts
More file actions
112 lines (97 loc) · 3.42 KB
/
Authorization.ts
File metadata and controls
112 lines (97 loc) · 3.42 KB
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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
import Axios, { AxiosResponse, AxiosError } from 'axios'
import * as log from 'log'
export interface AccessTokenResponse {
access_token: string
refresh_token: string
token_type: string
expires_in: number
}
export interface UserRecord {
userId: string
accessToken: string
refreshToken: string
accessTokenExpiry?: string
updatedAt?: string
email?: string
skillRegion?: string
isBlocked?: boolean
allowedDeviceCount?: number
plan?: string
stripeCustomerId?: string
paddleCustomerId?: string
deleteAtUnixTime?: number
}
export type PartialUserRecord = Pick<UserRecord, 'userId'> & Partial<UserRecord>
export async function fetchAccessAndRefreshToken(
event
): Promise<AccessTokenResponse> {
const data = `grant_type=authorization_code&code=${event.directive.payload.grant.code}&client_id=${process.env.ALEXA_CLIENT_ID}&client_secret=${process.env.ALEXA_CLIENT_SECRET}`
const url = 'https://api.amazon.com/auth/o2/token'
const response: AxiosResponse = await Axios.post(url, data, {
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
})
// console.log(':::fetchAccessAndRefreshToken:::')
// console.log(url)
// console.log(data)
// console.log(response.data)
// {
// "access_token":"Atza|IQEBLjAsAhRmHjNmHpi0U-Dme37rR6CuUpSR...",
// "token_type":"bearer",
// "expires_in":3600,
// "refresh_token":"Atzr|IQEBLzAtAhRxpMJxdwVz2Nn6f2y-tpJX3DeX..."
// }
return response.data
}
export async function fetchFreshAccessToken(
refreshToken: string
): Promise<AccessTokenResponse> {
const refreshTokenPrefix = refreshToken?.substring(0, 12) + '...'
const clientId = process.env.ALEXA_CLIENT_ID?.substring(0, 20) + '...'
try {
log.info('Attempting token refresh', {
refreshTokenPrefix,
clientId,
endpoint: 'https://api.amazon.com/auth/o2/token'
})
const response: AxiosResponse = await Axios.post(
'https://api.amazon.com/auth/o2/token',
`grant_type=refresh_token&refresh_token=${refreshToken}&client_id=${process.env.ALEXA_CLIENT_ID}&client_secret=${process.env.ALEXA_CLIENT_SECRET}`,
{
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
}
)
log.info('Token refresh successful', {
refreshTokenPrefix,
hasNewAccessToken: !!response.data.access_token,
hasNewRefreshToken: !!response.data.refresh_token,
expiresIn: response.data.expires_in
})
return response.data
} catch (error) {
const axiosError = error as AxiosError
log.error('Token refresh failed', {
refreshTokenPrefix,
clientId,
status: axiosError.response?.status,
statusText: axiosError.response?.statusText,
errorCode: axiosError.code,
errorMessage: axiosError.message,
responseData: axiosError.response?.data,
headers: axiosError.response?.headers,
url: axiosError.config?.url,
method: axiosError.config?.method
})
// Re-throw with enhanced error context
const enhancedError = new Error(`Token refresh failed: ${axiosError.response?.status} ${axiosError.response?.statusText}`)
enhancedError.name = 'TokenRefreshError'
;(enhancedError as any).originalError = error
;(enhancedError as any).refreshTokenPrefix = refreshTokenPrefix
;(enhancedError as any).status = axiosError.response?.status
;(enhancedError as any).responseData = axiosError.response?.data
throw enhancedError
}
}