this repo has no description
at main 146 lines 3.9 kB view raw
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}