-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #46 from Faithful-Resource-Pack/discord-auth-provider
[Webapp Vue App] Added Discord auth provider
- Loading branch information
Showing
3 changed files
with
143 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,22 +1,38 @@ | ||
PORT=8000 | ||
DEV=true | ||
VERBOSE=false | ||
|
||
FIRESTORM_URL=https://url-to-firesto.rm | ||
FIRESTORM_TOKEN=abcdefghijklmnopqrstuvwxyz | ||
|
||
DB_IMAGE_ROOT=https://database.faithfulpack.net | ||
|
||
VERBOSE=false | ||
PURGE_PASSWORD=password123 | ||
|
||
# disable cache for dev | ||
NO_CACHE=true | ||
|
||
# ==================== | ||
# INTEGRATIONS | ||
# ==================== | ||
|
||
# cloudflare | ||
CLOUDFLARE_EMAIL="" | ||
CLOUDFLARE_KEY="" | ||
CLOUDFLARE_PASSWORD="" | ||
PURGE_PASSWORD=password123 | ||
|
||
# curseforge | ||
CURSEFORGE_API_KEY="" | ||
|
||
# discord | ||
BOT_PASSWORD=test | ||
WEBHOOK_URL=https://discord.com/api/webhooks/123456789123456789/a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0 | ||
|
||
# ==================== | ||
# AUTH PROVIDERS | ||
# ==================== | ||
|
||
# needs quotes because dotenv limitations | ||
AUTH_URLS={"webapp": "http://localhost/"} | ||
|
||
# discord | ||
DISCORD_CLIENT_ID=abcdef123456789 | ||
DISCORD_CLIENT_SECRET=veryveryverysecret |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
import { Request as ExRequest, Response as ExResponse } from "express"; | ||
import { Body, Controller, Get, Path, Post, Query, Request, Route, Tags } from "tsoa"; | ||
import AuthService from "../service/auth.service"; | ||
|
||
@Route("auth") | ||
@Tags("Auth") | ||
export class AuthController extends Controller { | ||
private readonly service = new AuthService(); | ||
|
||
/** | ||
* Redirects to Discord oauth2 authorization page | ||
* @param target Redirect target app | ||
*/ | ||
@Get("discord/{target}") | ||
public discordAuthGrant(@Path() target: string, @Request() request: ExRequest) { | ||
const redirectURI = this.service.getRedirectURI(request, target); | ||
|
||
const response = (<any>request).res as ExResponse; | ||
const params = new URLSearchParams(); | ||
params.append("client_id", process.env.DISCORD_CLIENT_ID); | ||
params.append("response_type", "code"); | ||
params.append("scope", "identify"); | ||
params.append("redirect_uri", redirectURI); | ||
|
||
response.redirect(`https://discord.com/api/oauth2/authorize?${params.toString()}`); | ||
} | ||
|
||
/** | ||
* Handles Discord authorization page redirect | ||
* @param target Where to post the auth (provided in /auth/discord/{target}) | ||
*/ | ||
@Get("discord/callback/{target}") | ||
public async discordAuthCallback( | ||
@Path() target: string, | ||
@Query() code: string, | ||
@Request() request: ExRequest, | ||
) { | ||
const params = new URLSearchParams(); | ||
params.append("client_id", process.env.DISCORD_CLIENT_ID); | ||
params.append("client_secret", process.env.DISCORD_CLIENT_SECRET); | ||
params.append("grant_type", "authorization_code"); | ||
params.append("code", code); | ||
params.append("redirect_uri", `${this.service.getApiUrl(request)}${request.path}`); | ||
params.append("scope", "identify"); | ||
|
||
const res = (<any>request).res as ExResponse; | ||
const tokenResponse = await fetch("https://discord.com/api/oauth2/token", { | ||
method: "POST", | ||
body: params, | ||
}); | ||
|
||
const json: any = await tokenResponse.json(); | ||
|
||
if ("error" in json) { | ||
res.status(500).json(json).end(); | ||
return; | ||
} | ||
|
||
const redirect = new URLSearchParams(); | ||
redirect.append("access_token", json.access_token); | ||
redirect.append("refresh_token", json.refresh_token); | ||
redirect.append("expires_in", json.expires_in); | ||
res.redirect(`${this.service.targetToURL(target)}?${redirect.toString()}`); | ||
} | ||
|
||
/** | ||
* Handles Discord refresh for new sessions | ||
*/ | ||
@Post("discord/refresh") | ||
public async discordAuthRefresh(@Body() refresh_token: string, @Request() request: ExRequest) { | ||
const params = new URLSearchParams(); | ||
params.append("client_id", process.env.DISCORD_CLIENT_ID); | ||
params.append("client_secret", process.env.DISCORD_CLIENT_SECRET); | ||
params.append("grant_type", "refresh_token"); | ||
params.append("refresh_token", refresh_token); | ||
|
||
const res = (<any>request).res as ExResponse; | ||
const tokenResponse = await fetch("https://discord.com/api/oauth2/token", { | ||
method: "POST", | ||
body: params, | ||
}); | ||
|
||
const json: any = await tokenResponse.json(); | ||
|
||
if ("error" in json) { | ||
res.status(500).json(json).end(); | ||
return; | ||
} | ||
|
||
res.json(json).end(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import { Request as ExRequest } from "express"; | ||
import { NotFoundError } from "../tools/ApiError"; | ||
|
||
// REDIRECT URL IS '<origin>/auth/<provider>/callback/<target>' | ||
const REDIRECT_URI_PATHNAME = "/callback/"; | ||
// example with discord provider: | ||
// REDIRECT URL IS '<origin>/auth/discord/callback' | ||
|
||
export default class AuthService { | ||
getApiUrl(request: ExRequest): string { | ||
return `${request.protocol}://${request.headers.host}`; | ||
} | ||
|
||
rawTargetToURL(target: string): string { | ||
const url = JSON.parse(process.env.AUTH_URLS)[target]; | ||
if (!url) throw new NotFoundError("Target not found!"); | ||
return url; | ||
} | ||
|
||
targetToURL(target: string): string { | ||
return this.rawTargetToURL(target).replace(/\/$/, ""); | ||
} | ||
|
||
getRedirectURI(request: ExRequest, target: string): string { | ||
const apiOrigin = this.getApiUrl(request); | ||
const requestPath = request.path; | ||
const pathSplit = requestPath.split("/"); | ||
pathSplit.pop(); // remove target | ||
return `${apiOrigin.replace(/\/$/, "")}${pathSplit.join("/")}${REDIRECT_URI_PATHNAME}${target}`; | ||
} | ||
} |