fix: Azure single-tenant SSO tokens are unable to refresh (#5551)
This commit is contained in:
@@ -93,6 +93,7 @@ class UserAuthentication extends IdModel {
|
|||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
// Check a maximum of once every 5 minutes
|
// Check a maximum of once every 5 minutes
|
||||||
if (this.lastValidatedAt > subMinutes(Date.now(), 5) && !force) {
|
if (this.lastValidatedAt > subMinutes(Date.now(), 5) && !force) {
|
||||||
|
Logger.debug("utils", "Skipping access token validation");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,7 +159,10 @@ class UserAuthentication extends IdModel {
|
|||||||
|
|
||||||
const client = authenticationProvider.oauthClient;
|
const client = authenticationProvider.oauthClient;
|
||||||
if (client) {
|
if (client) {
|
||||||
const response = await client.rotateToken(this.refreshToken);
|
const response = await client.rotateToken(
|
||||||
|
this.accessToken,
|
||||||
|
this.refreshToken
|
||||||
|
);
|
||||||
|
|
||||||
// Not all OAuth providers return a new refreshToken so we need to guard
|
// Not all OAuth providers return a new refreshToken so we need to guard
|
||||||
// against setting to an empty value.
|
// against setting to an empty value.
|
||||||
|
|||||||
@@ -1,9 +1,36 @@
|
|||||||
|
import JWT from "jsonwebtoken";
|
||||||
|
import env from "@server/env";
|
||||||
import OAuthClient from "./oauth";
|
import OAuthClient from "./oauth";
|
||||||
|
|
||||||
|
type AzurePayload = {
|
||||||
|
/* A GUID that represents the Azure AD tenant that the user is from */
|
||||||
|
tid: string;
|
||||||
|
};
|
||||||
|
|
||||||
export default class AzureClient extends OAuthClient {
|
export default class AzureClient extends OAuthClient {
|
||||||
endpoints = {
|
endpoints = {
|
||||||
authorize: "https://login.microsoftonline.com/common/oauth2/v2.0/authorize",
|
authorize: "https://login.microsoftonline.com/common/oauth2/v2.0/authorize",
|
||||||
token: "https://login.microsoftonline.com/common/oauth2/v2.0/token",
|
token: "https://login.microsoftonline.com/common/oauth2/v2.0/token",
|
||||||
userinfo: "https://graph.microsoft.com/v1.0/me",
|
userinfo: "https://graph.microsoft.com/v1.0/me",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
async rotateToken(
|
||||||
|
accessToken: string,
|
||||||
|
refreshToken: string
|
||||||
|
): Promise<{
|
||||||
|
accessToken: string;
|
||||||
|
refreshToken?: string;
|
||||||
|
expiresAt: Date;
|
||||||
|
}> {
|
||||||
|
if (env.isCloudHosted()) {
|
||||||
|
return super.rotateToken(accessToken, refreshToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
const payload = JWT.decode(accessToken) as AzurePayload;
|
||||||
|
return super.rotateToken(
|
||||||
|
accessToken,
|
||||||
|
refreshToken,
|
||||||
|
`https://login.microsoftonline.com/${payload.tid}/oauth2/v2.0/token`
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import fetch from "fetch-with-proxy";
|
import fetch from "fetch-with-proxy";
|
||||||
|
import Logger from "@server/logging/Logger";
|
||||||
import { AuthenticationError, InvalidRequestError } from "../errors";
|
import { AuthenticationError, InvalidRequestError } from "../errors";
|
||||||
|
|
||||||
export default abstract class OAuthClient {
|
export default abstract class OAuthClient {
|
||||||
@@ -41,18 +42,22 @@ export default abstract class OAuthClient {
|
|||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
||||||
rotateToken = async (
|
async rotateToken(
|
||||||
refreshToken: string
|
_accessToken: string,
|
||||||
|
refreshToken: string,
|
||||||
|
endpoint = this.endpoints.token
|
||||||
): Promise<{
|
): Promise<{
|
||||||
accessToken: string;
|
accessToken: string;
|
||||||
refreshToken?: string;
|
refreshToken?: string;
|
||||||
expiresAt: Date;
|
expiresAt: Date;
|
||||||
}> => {
|
}> {
|
||||||
let data;
|
let data;
|
||||||
let response;
|
let response;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
response = await fetch(this.endpoints.token, {
|
Logger.debug("utils", "Rotating token", { endpoint });
|
||||||
|
|
||||||
|
response = await fetch(endpoint, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/x-www-form-urlencoded",
|
"Content-Type": "application/x-www-form-urlencoded",
|
||||||
@@ -79,5 +84,5 @@ export default abstract class OAuthClient {
|
|||||||
accessToken: data.access_token,
|
accessToken: data.access_token,
|
||||||
expiresAt: new Date(Date.now() + data.expires_in * 1000),
|
expiresAt: new Date(Date.now() + data.expires_in * 1000),
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user