this repo has no description
1import { generateCodeChallenge, verifier } from './oauth-pkce';
2
3const {
4 DEV,
5 PHANPY_CLIENT_NAME: CLIENT_NAME,
6 PHANPY_WEBSITE: WEBSITE,
7} = import.meta.env;
8
9const SCOPES = 'read write follow push';
10
11/*
12 PHANPY_WEBSITE is set to the default official site.
13 It's used in pre-built releases, so there's no way to change it dynamically
14 without rebuilding.
15 Therefore, we can't use it as redirect_uri.
16 We only use PHANPY_WEBSITE if it's "same" as current location URL.
17
18 Very basic check based on location.hostname for now
19*/
20const sameSite = WEBSITE
21 ? WEBSITE.toLowerCase().includes(location.hostname)
22 : false;
23const currentLocation = location.origin + location.pathname;
24const REDIRECT_URI = DEV || !sameSite ? currentLocation : WEBSITE;
25
26export async function registerApplication({ instanceURL }) {
27 const registrationParams = new URLSearchParams({
28 client_name: CLIENT_NAME,
29 redirect_uris: REDIRECT_URI,
30 scopes: SCOPES,
31 website: WEBSITE,
32 });
33 const registrationResponse = await fetch(
34 `https://${instanceURL}/api/v1/apps`,
35 {
36 method: 'POST',
37 headers: {
38 'Content-Type': 'application/x-www-form-urlencoded',
39 },
40 body: registrationParams.toString(),
41 },
42 );
43 const registrationJSON = await registrationResponse.json();
44 console.log({ registrationJSON });
45 return registrationJSON;
46}
47
48export async function getPKCEAuthorizationURL({
49 instanceURL,
50 client_id,
51 forceLogin = false,
52}) {
53 const codeVerifier = verifier();
54 const codeChallenge = await generateCodeChallenge(codeVerifier);
55 const params = new URLSearchParams({
56 client_id,
57 code_challenge_method: 'S256',
58 code_challenge: codeChallenge,
59 redirect_uri: REDIRECT_URI,
60 response_type: 'code',
61 scope: SCOPES,
62 });
63 if (forceLogin) params.append('force_login', true);
64 const authorizationURL = `https://${instanceURL}/oauth/authorize?${params.toString()}`;
65 return [authorizationURL, codeVerifier];
66}
67
68export async function getAuthorizationURL({
69 instanceURL,
70 client_id,
71 forceLogin = false,
72}) {
73 const authorizationParams = new URLSearchParams({
74 client_id,
75 scope: SCOPES,
76 redirect_uri: REDIRECT_URI,
77 // redirect_uri: 'urn:ietf:wg:oauth:2.0:oob',
78 response_type: 'code',
79 });
80 if (forceLogin) authorizationParams.append('force_login', true);
81 const authorizationURL = `https://${instanceURL}/oauth/authorize?${authorizationParams.toString()}`;
82 return authorizationURL;
83}
84
85export async function getAccessToken({
86 instanceURL,
87 client_id,
88 client_secret,
89 code,
90 code_verifier,
91}) {
92 const params = new URLSearchParams({
93 client_id,
94 redirect_uri: REDIRECT_URI,
95 grant_type: 'authorization_code',
96 code,
97 // scope: SCOPES, // Not needed
98 // client_secret,
99 // code_verifier,
100 });
101 if (client_secret) {
102 params.append('client_secret', client_secret);
103 }
104 if (code_verifier) {
105 params.append('code_verifier', code_verifier);
106 }
107 const tokenResponse = await fetch(`https://${instanceURL}/oauth/token`, {
108 method: 'POST',
109 headers: {
110 'Content-Type': 'application/x-www-form-urlencoded',
111 },
112 body: params.toString(),
113 });
114 const tokenJSON = await tokenResponse.json();
115 console.log({ tokenJSON });
116 return tokenJSON;
117}
118
119export async function revokeAccessToken({
120 instanceURL,
121 client_id,
122 client_secret,
123 token,
124}) {
125 try {
126 const params = new URLSearchParams({
127 client_id,
128 client_secret,
129 token,
130 });
131
132 const revokeResponse = await fetch(`https://${instanceURL}/oauth/revoke`, {
133 method: 'POST',
134 headers: {
135 'Content-Type': 'application/x-www-form-urlencoded',
136 },
137 body: params.toString(),
138 keepalive: true,
139 });
140
141 return revokeResponse.ok;
142 } catch (error) {
143 console.erro('Error revoking token', error);
144 return false;
145 }
146}