Skip to content

Commit

Permalink
Merge pull request #46 from Faithful-Resource-Pack/discord-auth-provider
Browse files Browse the repository at this point in the history
[Webapp Vue App] Added Discord auth provider
  • Loading branch information
TheRolfFR authored Feb 26, 2024
2 parents d59f2eb + d6a593f commit aeacef7
Show file tree
Hide file tree
Showing 3 changed files with 143 additions and 4 deletions.
24 changes: 20 additions & 4 deletions .env.example
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
92 changes: 92 additions & 0 deletions src/v2/controller/auth.controller.ts
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();
}
}
31 changes: 31 additions & 0 deletions src/v2/service/auth.service.ts
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}`;
}
}

0 comments on commit aeacef7

Please sign in to comment.