Skip to content

Commit 0652568

Browse files
committed
refresh token logic for expired access tokens
1 parent 8d26db1 commit 0652568

File tree

3 files changed

+46
-4
lines changed

3 files changed

+46
-4
lines changed

src/server/auth/custom-providers/etsy.ts

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { env } from "@/env";
22
import type { OAuth2Config, OAuthUserConfig } from "@auth/core/providers";
3+
import {db} from "@/server/db";
34

45
export interface EtsyProfile {
56
user_id: number; // The numeric ID of a user. Also a valid shop ID.
@@ -21,7 +22,7 @@ export default function EtsyProvider<P extends EtsyProfile>(
2122
authorization: {
2223
url: "https://www.etsy.com/oauth/connect",
2324
params: {
24-
scope: "email_r",
25+
scope: "email_r listing_r",
2526
state: Math.random().toString(36).substring(2, 15),
2627
},
2728
},
@@ -63,3 +64,38 @@ export default function EtsyProvider<P extends EtsyProfile>(
6364
options,
6465
};
6566
}
67+
68+
export async function refreshEtsyAccessToken(
69+
refreshToken: string,
70+
providerAccountId: string
71+
) {
72+
const response = await fetch("https://api.etsy.com/v3/public/oauth/token", {
73+
method: "POST",
74+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
75+
body: new URLSearchParams({
76+
grant_type: "refresh_token",
77+
client_id: process.env.AUTH_ETSY_ID!, // your app's client_id
78+
refresh_token: refreshToken, // the one you stored
79+
}),
80+
});
81+
if (!response.ok) {
82+
throw new Error("Failed to refresh Etsy access token");
83+
}
84+
const tokens = await response.json();
85+
86+
await db.account.update({
87+
where: {
88+
provider_providerAccountId: {
89+
provider: "etsy",
90+
providerAccountId: providerAccountId,
91+
},
92+
},
93+
data: {
94+
access_token: tokens.access_token,
95+
refresh_token: tokens.refresh_token,
96+
scope: tokens.scope,
97+
token_type: tokens.token_type,
98+
expires_at: tokens.expires_at,
99+
},
100+
});
101+
}

src/toolkits/toolkits/Etsy/tools/getListing/server.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type { ServerToolConfig } from "@/toolkits/types";
22
import type { getListing } from "./base";
33
import { api } from "@/trpc/server";
4+
import { refreshEtsyAccessToken} from "@/server/auth/custom-providers/etsy";
45

56

67
export const getListingServerConfig = (
@@ -16,12 +17,18 @@ export const getListingServerConfig = (
1617
const userID = account?.providerAccountId;
1718
const etsyUserId = Number(userID);
1819
const apiKey = process.env.AUTH_ETSY_ID;
20+
const refreshToken = account?.refresh_token;
21+
const accessExpiry = account?.expires_at;
22+
1923
if (!apiKey) throw new Error("Missing AUTH_ETSY_ID");
24+
if (accessExpiry && refreshToken && userID && (accessExpiry < Date.now() / 1000)) {
25+
await refreshEtsyAccessToken(refreshToken, userID);
26+
}
27+
2028
const accessToken = account?.access_token;
2129
if (!accessToken) throw new Error("Missing Etsy access token");
2230

2331

24-
2532
const shopResponse = await fetch(
2633
`https://openapi.etsy.com/v3/application/users/${etsyUserId}/shops`,
2734
{

src/toolkits/toolkits/Etsy/wrapper.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,14 @@ export const EtsyWrapper: ClientToolkitWrapper = ({ Item }) => {
2020
const { data: hasAccount, isLoading } =
2121
api.accounts.hasProviderAccount.useQuery("etsy");
2222

23-
2423
const [isAuthRequiredDialogOpen, setIsAuthRequiredDialogOpen] =
2524
useState(false);
2625

2726
if (isLoading) {
2827
return <Item isLoading={true} />;
2928
}
3029

31-
if (!hasAccount || true) {
30+
if (!hasAccount) {
3231
return (
3332
<>
3433
<Item

0 commit comments

Comments
 (0)