refactor: better auth code
This commit is contained in:
parent
76a058a312
commit
ff7cf961f2
@ -12,39 +12,109 @@ interface TokenResponse {
|
|||||||
scope: string,
|
scope: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const discord = {
|
class OauthConfig {
|
||||||
name: 'discord',
|
clientId: string;
|
||||||
getAuthUrl: (state: string, scopes: string[] = []) => {
|
clientSecret: string;
|
||||||
const client_id = env.DISCORD_CLIENT_ID
|
|
||||||
const redir_uri = encodeURIComponent(callbackUrl)
|
authUrl: URL;
|
||||||
const scope = scopes.join("+")
|
tokenUrl: URL;
|
||||||
return `https://discord.com/oauth2/authorize?client_id=${client_id}&response_type=code&redirect_uri=${redir_uri}&scope=${scope}&state=${state}`
|
|
||||||
},
|
joinScopes: (scopes: string[]) => string = (scopes) => scopes.join("+");
|
||||||
getToken: async (code: string): Promise<TokenResponse> => {
|
getAuthParams: (params: Record<string, string>, config: OauthConfig) => Record<string, string> = (params) => { return params };
|
||||||
const api = `https://discord.com/api/oauth2/token`
|
getTokenParams: (params: Record<string, string>, config: OauthConfig) => Record<string, string> = (params) => { return params };
|
||||||
const body = new URLSearchParams({
|
extractTokenResponse: (tokenResp: any) => TokenResponse = (tokenResp) => {
|
||||||
client_id: env.DISCORD_CLIENT_ID,
|
|
||||||
client_secret: env.DISCORD_CLIENT_SECRET,
|
|
||||||
grant_type: 'authorization_code',
|
|
||||||
redirect_uri: callbackUrl,
|
|
||||||
code,
|
|
||||||
})
|
|
||||||
const resp = await fetch(api, { method: 'POST', body })
|
|
||||||
if (resp.status !== 200) {
|
|
||||||
throw new Error("woopsies, couldnt get oauth token")
|
|
||||||
}
|
|
||||||
const tokenResp: any = await resp.json()
|
|
||||||
return {
|
return {
|
||||||
accessToken: tokenResp.access_token,
|
accessToken: tokenResp.access_token,
|
||||||
tokenType: tokenResp.token_type,
|
tokenType: tokenResp.token_type,
|
||||||
scope: tokenResp.scope,
|
scope: tokenResp.scope,
|
||||||
}
|
}
|
||||||
},
|
};
|
||||||
|
|
||||||
|
tokenReqHeaders: Record<string, string> = {};
|
||||||
|
|
||||||
|
constructor(clientId: string, clientSecret: string, authUrl: URL | string, tokenUrl: URL | string) {
|
||||||
|
this.clientId = clientId;
|
||||||
|
this.clientSecret = clientSecret;
|
||||||
|
this.authUrl = typeof authUrl === 'string' ? new URL(authUrl) : authUrl
|
||||||
|
this.tokenUrl = typeof tokenUrl === 'string' ? new URL(tokenUrl) : tokenUrl
|
||||||
|
}
|
||||||
|
|
||||||
|
withJoinScopes(f: typeof this.joinScopes) {
|
||||||
|
this.joinScopes = f
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
withGetAuthParams(f: typeof this.getAuthParams) {
|
||||||
|
this.getAuthParams = f
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
withGetTokenParams(f: typeof this.getTokenParams) {
|
||||||
|
this.getTokenParams = f
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
withExtractTokenResponse(f: typeof this.extractTokenResponse) {
|
||||||
|
this.extractTokenResponse = f
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
withTokenRequestHeaders(f: typeof this.tokenReqHeaders) {
|
||||||
|
this.tokenReqHeaders = f
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const genericOauthClient = (oauthConfig: OauthConfig) => {
|
||||||
|
return {
|
||||||
|
getAuthUrl: (state: string, scopes: string[] = []) => {
|
||||||
|
const redirect_uri = callbackUrl
|
||||||
|
const scope = oauthConfig.joinScopes(scopes)
|
||||||
|
const baseParams = {
|
||||||
|
client_id: oauthConfig.clientId,
|
||||||
|
redirect_uri,
|
||||||
|
scope,
|
||||||
|
state,
|
||||||
|
}
|
||||||
|
const params = oauthConfig.getAuthParams(baseParams, oauthConfig)
|
||||||
|
const urlParams = new URLSearchParams(params)
|
||||||
|
const urlRaw = `${oauthConfig.authUrl}?${urlParams.toString()}`
|
||||||
|
return new URL(urlRaw)
|
||||||
|
},
|
||||||
|
getToken: async (code: string): Promise<TokenResponse> => {
|
||||||
|
const api = oauthConfig.tokenUrl
|
||||||
|
const baseParams = {
|
||||||
|
client_id: oauthConfig.clientId,
|
||||||
|
client_secret: oauthConfig.clientSecret,
|
||||||
|
redirect_uri: callbackUrl,
|
||||||
|
code,
|
||||||
|
}
|
||||||
|
const body = new URLSearchParams(oauthConfig.getTokenParams(baseParams, oauthConfig))
|
||||||
|
const resp = await fetch(api, { method: 'POST', body, headers: oauthConfig.tokenReqHeaders })
|
||||||
|
if (resp.status !== 200) {
|
||||||
|
throw new Error("woopsies, couldnt get oauth token")
|
||||||
|
}
|
||||||
|
const tokenResp: any = await resp.json()
|
||||||
|
return oauthConfig.extractTokenResponse(tokenResp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const discord = {
|
||||||
|
name: 'discord',
|
||||||
|
...genericOauthClient(
|
||||||
|
new OauthConfig(
|
||||||
|
env.DISCORD_CLIENT_ID,
|
||||||
|
env.DISCORD_CLIENT_SECRET,
|
||||||
|
'https://discord.com/oauth2/authorize',
|
||||||
|
'https://discord.com/api/oauth2/token',
|
||||||
|
)
|
||||||
|
.withGetAuthParams((params) => { return { ...params, response_type: 'code', prompt: 'none' } })
|
||||||
|
.withGetTokenParams((params) => { return { ...params, grant_type: 'authorization_code' } })
|
||||||
|
),
|
||||||
identifyToken: async (tokenResp: TokenResponse): Promise<string> => {
|
identifyToken: async (tokenResp: TokenResponse): Promise<string> => {
|
||||||
const api = `https://discord.com/api/users/@me`
|
const api = `https://discord.com/api/users/@me`
|
||||||
const resp = await fetch(api, {headers: {
|
const resp = await fetch(api, {
|
||||||
'Authorization': `${tokenResp.tokenType} ${tokenResp.accessToken}`
|
headers: {
|
||||||
}})
|
'Authorization': `${tokenResp.tokenType} ${tokenResp.accessToken}`
|
||||||
|
}
|
||||||
|
})
|
||||||
if (resp.status !== 200) {
|
if (resp.status !== 200) {
|
||||||
throw new Error("woopsies, couldnt validate access token")
|
throw new Error("woopsies, couldnt validate access token")
|
||||||
}
|
}
|
||||||
@ -52,38 +122,26 @@ export const discord = {
|
|||||||
return body.username
|
return body.username
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const github = {
|
export const github = {
|
||||||
name: 'github',
|
name: 'github',
|
||||||
getAuthUrl: (state: string, scopes: string[] = []) => {
|
...genericOauthClient(
|
||||||
const client_id = env.GITHUB_CLIENT_ID
|
new OauthConfig(
|
||||||
const redir_uri = encodeURIComponent(callbackUrl)
|
env.GITHUB_CLIENT_ID,
|
||||||
const scope = encodeURIComponent(scopes.join(" "))
|
env.GITHUB_CLIENT_SECRET,
|
||||||
return `https://github.com/login/oauth/authorize?client_id=${client_id}&redirect_uri=${redir_uri}&scope=${scope}&state=${state}`
|
'https://github.com/login/oauth/authorize',
|
||||||
},
|
'https://github.com/login/oauth/access_token',
|
||||||
getToken: async (code: string): Promise<TokenResponse> => {
|
)
|
||||||
const api = `https://github.com/login/oauth/access_token`
|
.withJoinScopes((s) => { return s.join(" ") })
|
||||||
const body = new URLSearchParams({
|
.withTokenRequestHeaders({ 'Accept': 'application/json' })
|
||||||
client_id: env.GITHUB_CLIENT_ID,
|
),
|
||||||
client_secret: env.GITHUB_CLIENT_SECRET,
|
|
||||||
redirect_uri: callbackUrl,
|
|
||||||
code,
|
|
||||||
})
|
|
||||||
const resp = await fetch(api, { method: 'POST', body, headers: { 'Accept': 'application/json' } })
|
|
||||||
if (resp.status !== 200) {
|
|
||||||
throw new Error("woopsies, couldnt get oauth token")
|
|
||||||
}
|
|
||||||
const tokenResp: any = await resp.json()
|
|
||||||
return {
|
|
||||||
accessToken: tokenResp.access_token,
|
|
||||||
tokenType: tokenResp.token_type,
|
|
||||||
scope: tokenResp.scope,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
identifyToken: async (tokenResp: TokenResponse): Promise<string> => {
|
identifyToken: async (tokenResp: TokenResponse): Promise<string> => {
|
||||||
const api = `https://api.github.com/user`
|
const api = `https://api.github.com/user`
|
||||||
const resp = await fetch(api, {headers: {
|
const resp = await fetch(api, {
|
||||||
'Authorization': `${tokenResp.tokenType} ${tokenResp.accessToken}`
|
headers: {
|
||||||
}})
|
'Authorization': `${tokenResp.tokenType} ${tokenResp.accessToken}`
|
||||||
|
}
|
||||||
|
})
|
||||||
if (resp.status !== 200) {
|
if (resp.status !== 200) {
|
||||||
throw new Error("woopsies, couldnt validate access token")
|
throw new Error("woopsies, couldnt validate access token")
|
||||||
}
|
}
|
||||||
@ -130,10 +188,10 @@ export const getAuthClient = (name: string) => {
|
|||||||
switch (name) {
|
switch (name) {
|
||||||
case "discord":
|
case "discord":
|
||||||
return discord
|
return discord
|
||||||
|
|
||||||
case "github":
|
case "github":
|
||||||
return github
|
return github
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,14 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
const title = getTitle(data.route);
|
const title = getTitle(data.route);
|
||||||
|
|
||||||
|
const svgSquiggles = [
|
||||||
|
[2],
|
||||||
|
[3],
|
||||||
|
[2],
|
||||||
|
[3],
|
||||||
|
[1],
|
||||||
|
]
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:head>
|
<svelte:head>
|
||||||
@ -65,26 +73,12 @@
|
|||||||
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" class="absolute -z-50">
|
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" class="absolute -z-50">
|
||||||
<defs>
|
<defs>
|
||||||
<filter id="squiggly-0">
|
{#each svgSquiggles as [scale], index}
|
||||||
<feTurbulence id="turbulence" baseFrequency="0.02" numOctaves="3" result="noise" seed="0" />
|
<filter id="squiggly-{index}">
|
||||||
<feDisplacementMap id="displacement" in="SourceGraphic" in2="noise" scale="2" />
|
<feTurbulence id="turbulence" baseFrequency="0.02" numOctaves="3" result="noise" seed={index} />
|
||||||
</filter>
|
<feDisplacementMap in="SourceGraphic" in2="noise" {scale} />
|
||||||
<filter id="squiggly-1">
|
|
||||||
<feTurbulence id="turbulence" baseFrequency="0.02" numOctaves="3" result="noise" seed="1" />
|
|
||||||
<feDisplacementMap in="SourceGraphic" in2="noise" scale="3" />
|
|
||||||
</filter>
|
|
||||||
<filter id="squiggly-2">
|
|
||||||
<feTurbulence id="turbulence" baseFrequency="0.02" numOctaves="3" result="noise" seed="2" />
|
|
||||||
<feDisplacementMap in="SourceGraphic" in2="noise" scale="2" />
|
|
||||||
</filter>
|
|
||||||
<filter id="squiggly-3">
|
|
||||||
<feTurbulence id="turbulence" baseFrequency="0.02" numOctaves="3" result="noise" seed="3" />
|
|
||||||
<feDisplacementMap in="SourceGraphic" in2="noise" scale="3" />
|
|
||||||
</filter>
|
|
||||||
<filter id="squiggly-4">
|
|
||||||
<feTurbulence id="turbulence" baseFrequency="0.02" numOctaves="3" result="noise" seed="4" />
|
|
||||||
<feDisplacementMap in="SourceGraphic" in2="noise" scale="1" />
|
|
||||||
</filter>
|
</filter>
|
||||||
|
{/each}
|
||||||
</defs>
|
</defs>
|
||||||
</svg>
|
</svg>
|
||||||
|
|
||||||
@ -92,7 +86,7 @@
|
|||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<nav class="w-full max-h-[6vh] fixed bottom-0 z-10 bg-ralsei-black">
|
<nav class="w-full min-h-[5vh] max-h-[6vh] fixed bottom-0 z-10 bg-ralsei-black">
|
||||||
<div
|
<div
|
||||||
class="
|
class="
|
||||||
max-w-full max-h-fit p-1 overflow-auto
|
max-w-full max-h-fit p-1 overflow-auto
|
||||||
|
Loading…
Reference in New Issue
Block a user