diff --git a/package-lock.json b/package-lock.json
index f333ef80711ff47a9404a6d5ddb09c141c83df62..47e48f9074f4eeefdb2a0460256863defb568c13 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -12340,9 +12340,9 @@
}
},
"node_modules/jose": {
- "version": "4.15.9",
- "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.9.tgz",
- "integrity": "sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA==",
+ "version": "5.9.6",
+ "resolved": "https://registry.npmjs.org/jose/-/jose-5.9.6.tgz",
+ "integrity": "sha512-AMlnetc9+CV9asI19zHmrgS/WYsWUwCn2R7RzlbJWD7F9eWYUTGyBmU9o6PxngtLGOiDGPRu+Uc4fhKzbpteZQ==",
"funding": {
"url": "https://github.com/sponsors/panva"
}
@@ -12574,17 +12574,6 @@
"loose-envify": "cli.js"
}
},
- "node_modules/lru-cache": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
- "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
- "dependencies": {
- "yallist": "^4.0.0"
- },
- "engines": {
- "node": ">=10"
- }
- },
"node_modules/magic-string": {
"version": "0.30.8",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.8.tgz",
@@ -12916,6 +12905,14 @@
"node": ">=0.10.0"
}
},
+ "node_modules/oauth4webapi": {
+ "version": "3.1.4",
+ "resolved": "https://registry.npmjs.org/oauth4webapi/-/oauth4webapi-3.1.4.tgz",
+ "integrity": "sha512-eVfN3nZNbok2s/ROifO0UAc5G8nRoLSbrcKJ09OqmucgnhXEfdIQOR4gq1eJH1rN3gV7rNw62bDEgftsgFtBEg==",
+ "funding": {
+ "url": "https://github.com/sponsors/panva"
+ }
+ },
"node_modules/object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
@@ -13036,14 +13033,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/oidc-token-hash": {
- "version": "5.0.3",
- "resolved": "https://registry.npmjs.org/oidc-token-hash/-/oidc-token-hash-5.0.3.tgz",
- "integrity": "sha512-IF4PcGgzAr6XXSff26Sk/+P4KZFJVuHAJZj3wgO3vX2bMdNVp/QXTP3P7CEm9V1IdG8lDLY3HhiqpsE/nOwpPw==",
- "engines": {
- "node": "^10.13.0 || >=12.0.0"
- }
- },
"node_modules/on-finished": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
@@ -13081,27 +13070,17 @@
}
},
"node_modules/openid-client": {
- "version": "5.7.1",
- "resolved": "https://registry.npmjs.org/openid-client/-/openid-client-5.7.1.tgz",
- "integrity": "sha512-jDBPgSVfTnkIh71Hg9pRvtJc6wTwqjRkN88+gCFtYWrlP4Yx2Dsrow8uPi3qLr/aeymPF3o2+dS+wOpglK04ew==",
+ "version": "6.1.7",
+ "resolved": "https://registry.npmjs.org/openid-client/-/openid-client-6.1.7.tgz",
+ "integrity": "sha512-JfY/KvQgOutmG2P+oVNKInE7zIh+im1MQOaO7g5CtNnTWMociA563WweiEMKfR9ry9XG3K2HGvj9wEqhCQkPMg==",
"dependencies": {
- "jose": "^4.15.9",
- "lru-cache": "^6.0.0",
- "object-hash": "^2.2.0",
- "oidc-token-hash": "^5.0.3"
+ "jose": "^5.9.6",
+ "oauth4webapi": "^3.1.4"
},
"funding": {
"url": "https://github.com/sponsors/panva"
}
},
- "node_modules/openid-client/node_modules/object-hash": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz",
- "integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==",
- "engines": {
- "node": ">= 6"
- }
- },
"node_modules/optionator": {
"version": "0.9.3",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz",
@@ -16664,7 +16643,7 @@
"express": "^4.21.2",
"express-rate-limit": "^7.5.0",
"express-session": "^1.18.1",
- "openid-client": "^5.7.1",
+ "openid-client": "^6.1.7",
"prom-client": "^15.1.3",
"rate-limit-redis": "^4.2.0",
"redis": "^4.7.0",
diff --git a/packages/client/src/components/AuthErrors.tsx b/packages/client/src/components/AuthErrors.tsx
index 934730d96d3f9e26d9eb6b55197ad9d9a02e2d4b..6a9d6ff3b3f1a8548b36b0598b0881dc13b59a81 100644
--- a/packages/client/src/components/AuthErrors.tsx
+++ b/packages/client/src/components/AuthErrors.tsx
@@ -35,11 +35,6 @@ export const AuthErrors = () => {
return (
<>
-
void;
- params: URLSearchParams;
-}) => {
- return (
-
-
- {(onClose) => (
- <>
- Login Error
-
- Error: {params.get(Params.ERROR)}
-
-
- Error Description: {params.get(Params.ERROR_DESC)}
-
-
-
-
- >
- )}
-
-
- );
-};
-
/**
* This is for OP errors, these might not be retryable
* @param param0
diff --git a/packages/server/package.json b/packages/server/package.json
index fb8772094ffad79ab8fad879f06c48bf81cc4b6f..c7788be163f6bd6c780a95dd70dbbec47db8b240 100644
--- a/packages/server/package.json
+++ b/packages/server/package.json
@@ -38,7 +38,7 @@
"express": "^4.21.2",
"express-rate-limit": "^7.5.0",
"express-session": "^1.18.1",
- "openid-client": "^5.7.1",
+ "openid-client": "^6.1.7",
"prom-client": "^15.1.3",
"rate-limit-redis": "^4.2.0",
"redis": "^4.7.0",
diff --git a/packages/server/src/api/client.ts b/packages/server/src/api/client.ts
index 97897fe553104e69050fba4c214912f75c7cff07..0fe592c3c23f3d939e8ad4e29e9a02c7331b5bdc 100644
--- a/packages/server/src/api/client.ts
+++ b/packages/server/src/api/client.ts
@@ -1,7 +1,7 @@
import { Router } from "express";
import { prisma } from "../lib/prisma";
import { OpenID } from "../lib/oidc";
-import { TokenSet, errors as OIDC_Errors } from "openid-client";
+import { ResponseBodyError } from "openid-client";
import { getLogger } from "../lib/Logger";
import Canvas from "../lib/Canvas";
import { RateLimiter } from "../lib/RateLimiter";
@@ -44,12 +44,7 @@ app.get("/login", (req, res) => {
return;
}
- res.redirect(
- OpenID.client.authorizationUrl({
- prompt: "consent",
- scope: "openid instance",
- })
- );
+ res.redirect(OpenID.getAuthorizationURL());
});
app.get("/logout", (req, res) => {
@@ -78,34 +73,19 @@ app.get("/callback", RateLimiter.HIGH, async (req, res) => {
return;
}
- let exchange: TokenSet;
+ let exchange: Awaited>;
try {
- const params = OpenID.client.callbackParams(req);
- exchange = await OpenID.client.callback(OpenID.getRedirectUrl(), params);
+ exchange = await OpenID.exchangeToken(req.originalUrl);
} catch (e) {
- if (e instanceof OIDC_Errors.RPError) {
- // client error
-
- res.redirect(
- "/" +
- buildQuery({
- TYPE: "rp",
- ERROR: e.name,
- ERROR_DESC: e.message,
- })
- );
- return;
- }
-
- if (e instanceof OIDC_Errors.OPError) {
- // server error
+ console.error(e);
+ if (e instanceof ResponseBodyError) {
switch (e.error) {
case "invalid_client":
// this happens when we're configured with invalid credentials
Logger.error(
- "OpenID is improperly configured. Cannot exchange tokens, do I have valid credetials?"
+ "OpenID is improperly configured. Cannot exchange tokens, do I have valid credentials?"
);
res.redirect(
"/" +
@@ -127,16 +107,6 @@ app.get("/callback", RateLimiter.HIGH, async (req, res) => {
);
return;
}
-
- res.redirect(
- "/" +
- buildQuery({
- TYPE: "op",
- ERROR: e.error,
- ERROR_DESC: e.error_description,
- })
- );
- return;
}
res.redirect(
@@ -158,7 +128,7 @@ app.get("/callback", RateLimiter.HIGH, async (req, res) => {
}
try {
- const whoami = await OpenID.client.userinfo<{
+ const whoami = await OpenID.userInfo<{
instance: {
software: {
name: string;
@@ -173,7 +143,7 @@ app.get("/callback", RateLimiter.HIGH, async (req, res) => {
name?: string;
};
};
- }>(exchange.access_token);
+ }>(exchange.access_token, exchange.claims()!.sub);
const [username, hostname] = whoami.sub.split("@");
diff --git a/packages/server/src/lib/oidc.ts b/packages/server/src/lib/oidc.ts
index 92447d029c2db27bd25f597e0940fa75b8781d93..a29e5b4d3c5a9c62e2884ab4267b22616156b934 100644
--- a/packages/server/src/lib/oidc.ts
+++ b/packages/server/src/lib/oidc.ts
@@ -1,8 +1,7 @@
-import { BaseClient, Issuer } from "openid-client";
+import * as openid from "openid-client";
class OpenID_ {
- issuer: Issuer = {} as any;
- client: BaseClient = {} as any;
+ config: openid.Configuration = {} as any;
async setup() {
if (process.env.INHIBIT_LOGIN) {
@@ -14,18 +13,38 @@ class OpenID_ {
const { AUTH_ENDPOINT, AUTH_CLIENT, AUTH_SECRET } = process.env;
- this.issuer = await Issuer.discover(AUTH_ENDPOINT);
- this.client = new this.issuer.Client({
- client_id: AUTH_CLIENT,
+ this.config = await openid.discovery(new URL(AUTH_ENDPOINT), AUTH_CLIENT, {
client_secret: AUTH_SECRET,
- response_types: ["code"],
- redirect_uris: [this.getRedirectUrl()],
});
}
getRedirectUrl() {
return process.env.OIDC_CALLBACK_HOST + "/api/callback";
}
+
+ getAuthorizationURL() {
+ return openid
+ .buildAuthorizationUrl(this.config, {
+ redirect_uri: this.getRedirectUrl(),
+ prompt: "consent",
+ scope: "openid instance",
+ })
+ .toString();
+ }
+
+ exchangeToken(relativePath: string) {
+ return openid.authorizationCodeGrant(
+ this.config,
+ new URL(relativePath, process.env.OIDC_CALLBACK_HOST)
+ );
+ }
+
+ userInfo(
+ accessToken: string,
+ expectedSub: string
+ ): Promise {
+ return openid.fetchUserInfo(this.config, accessToken, expectedSub) as any;
+ }
}
export const OpenID = new OpenID_();