Skip to content

Commit

Permalink
Xavier/clerk integration (#153)
Browse files Browse the repository at this point in the history
* Set up Clerk

* Set up Clerk

* Fix some errors apparently

* Cleaned up backend

* Cleaned up backend

* Removed passlink

* Renamed middleware

* Added codespaces support

* Fixed type issues

---------

Co-authored-by: “xavilien” <“[email protected]”>
  • Loading branch information
Xavilien and “xavilien” authored May 18, 2024
1 parent 68bcded commit affebe8
Show file tree
Hide file tree
Showing 27 changed files with 2,560 additions and 1,260 deletions.
20 changes: 0 additions & 20 deletions backend/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,12 @@ import "dotenv/config";
import morgan from "morgan";
import express, { ErrorRequestHandler } from "express";
import cors from "cors";
import { generateSigningRequestHandler, KeyStore } from "passlink-server";
import { isUser } from "./controllers/user.mjs";
import { getAllCourses, getCourseByID, getCourses, getFilteredCourses } from "./controllers/courses.mjs";
import { getFCEs } from "./controllers/fces.mjs";
import { getInstructors } from "./controllers/instructors.mjs";

// because there is a bug in the typing for passlink
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
KeyStore.readKey(process.env.LOGIN_API_KEY);

const app = express();
const signingRequestHandler = generateSigningRequestHandler(
{
redirectUrl: "",
restrictDomain: true,
applicationId: process.env.LOGIN_API_ID ?? "",
},
KeyStore.getSecretKey(),
true,
);

const port = process.env.PORT || 3000;

app.use(cors());
Expand All @@ -32,10 +16,6 @@ app.use(express.urlencoded({ extended: true }));
app.use(express.json());
app.use(morgan("dev"));

app.get("/signingrequest", (req, res) => {
signingRequestHandler(req, res);
});

app.route("/course/:courseID").get(getCourseByID);
app.route("/courses").get(getCourses);
app.route("/courses").post(isUser, getCourses);
Expand Down
35 changes: 14 additions & 21 deletions backend/src/controllers/user.mts
Original file line number Diff line number Diff line change
@@ -1,34 +1,27 @@
import * as jose from "jose";
import axios from "axios";
import cron from "node-cron";
import { NextFunction, Request, Response } from "express";

let JWT_PUBKEY: jose.KeyLike | undefined;

async function fetchLoginKey() {
const pubkey = (await axios.get("https://login.scottylabs.org/login/pubkey")).data;

JWT_PUBKEY = await jose.importSPKI(pubkey, "RS256");
return JWT_PUBKEY;
}

if (!JWT_PUBKEY) fetchLoginKey();

async function getLoginKey(): Promise<jose.KeyLike> {
return JWT_PUBKEY ?? (await fetchLoginKey());
}
const verifyUserToken = async (token: string) => {
const pubkey = process.env.CLERK_PEM_KEY || "";

cron.schedule("0 0 * * *", fetchLoginKey);
const JWT_PUBKEY = await jose.importSPKI(pubkey, "RS256");

const verifyUserToken = async (token: string) => {
const { payload } = await jose.jwtVerify(token, await getLoginKey(), {
const { payload } = await jose.jwtVerify(token, JWT_PUBKEY, {
algorithms: ["RS256"]
});

const currentTime = Math.floor(Date.now() / 1000);
const BACKEND_ENV = process.env.BACKEND_ENV || "dev";
const CLERK_LOGIN_HOST = process.env.CLERK_LOGIN_HOST || "http://localhost:3010";

if (!payload) {
throw "No token present. Did you forget to pass in the token with the API call?";
} else if (payload.applicationId !== process.env.LOGIN_API_ID || !payload.email) {
throw "Bad token";
} else if (payload.exp && payload.exp < currentTime) {
throw "Token has expired.";
} else if (payload.nbf && payload.nbf > currentTime) {
throw "Token is not valid yet.";
} else if (BACKEND_ENV === "prod" && payload.azp && payload.azp !== CLERK_LOGIN_HOST) {
throw "Token is not valid for this host.";
}
};

Expand Down
1 change: 1 addition & 0 deletions frontend/next-env.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
/// <reference types="next/navigation-types/compat/navigation" />

// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.
9 changes: 5 additions & 4 deletions frontend/next.config.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
require("dotenv").config({ path: "../.env" });
const withTM = require("next-transpile-modules")(["passlink"]);
const { PHASE_DEVELOPMENT_SERVER } = require("next/constants");

module.exports = (phase, defaultConfig) =>
withTM({
module.exports = (phase) => {
return {
env: {
backendUrl:
process.env.BACKEND_URL ||
process.env.CODESPACES && `https://${process.env.CODESPACE_NAME}-3000.app.github.dev` ||
(phase === PHASE_DEVELOPMENT_SERVER
? "http://localhost:3000"
: "https://course-tool-backend-2kh6wuzobq-uc.a.run.app"),
},
});
};
}
Loading

0 comments on commit affebe8

Please sign in to comment.