diff --git a/spec/unit/oidc/validate.spec.ts b/spec/unit/oidc/validate.spec.ts index e1f85fa08..a3fde6ee4 100644 --- a/spec/unit/oidc/validate.spec.ts +++ b/spec/unit/oidc/validate.spec.ts @@ -125,6 +125,8 @@ describe("validateOIDCIssuerWellKnown", () => { response_types_supported: ["code"], grant_types_supported: ["authorization_code"], code_challenge_methods_supported: ["S256"], + account_management_uri: "https://authorize.org/account", + account_management_actions_supported: ["org.matrix.cross_signing_reset"], }; beforeEach(() => { // stub to avoid console litter @@ -157,6 +159,8 @@ describe("validateOIDCIssuerWellKnown", () => { authorizationEndpoint: validWk.authorization_endpoint, tokenEndpoint: validWk.token_endpoint, registrationEndpoint: validWk.registration_endpoint, + accountManagementActionsSupported: ["org.matrix.cross_signing_reset"], + accountManagementEndpoint: "https://authorize.org/account", }); }); @@ -167,6 +171,8 @@ describe("validateOIDCIssuerWellKnown", () => { authorizationEndpoint: validWk.authorization_endpoint, tokenEndpoint: validWk.token_endpoint, registrationEndpoint: undefined, + accountManagementActionsSupported: ["org.matrix.cross_signing_reset"], + accountManagementEndpoint: "https://authorize.org/account", }); }); @@ -186,6 +192,8 @@ describe("validateOIDCIssuerWellKnown", () => { ["code_challenge_methods_supported", undefined], ["code_challenge_methods_supported", "not an array"], ["code_challenge_methods_supported", ["doesnt include S256"]], + ["account_management_uri", { not: "a string" }], + ["account_management_actions_supported", { not: "an array" }], ])("should throw OP support error when %s is %s", (key, value) => { const wk = { ...validWk, diff --git a/src/oidc/validate.ts b/src/oidc/validate.ts index a0d062e47..c806ca807 100644 --- a/src/oidc/validate.ts +++ b/src/oidc/validate.ts @@ -31,6 +31,8 @@ export type ValidatedIssuerConfig = { authorizationEndpoint: string; tokenEndpoint: string; registrationEndpoint?: string; + accountManagementEndpoint?: string; + accountManagementActionsSupported?: string[]; }; /** @@ -74,6 +76,16 @@ const optionalStringProperty = (wellKnown: Record, key: string) } return true; }; +const optionalStringArrayProperty = (wellKnown: Record, key: string): boolean => { + if ( + !!wellKnown[key] && + (!Array.isArray(wellKnown[key]) || !(wellKnown[key]).every((v) => typeof v === "string")) + ) { + logger.error(`Invalid property: ${key}`); + return false; + } + return true; +}; const requiredArrayValue = (wellKnown: Record, key: string, value: any): boolean => { const array = wellKnown[key]; if (!array || !Array.isArray(array) || !array.includes(value)) { @@ -102,6 +114,8 @@ export const validateOIDCIssuerWellKnown = (wellKnown: unknown): ValidatedIssuer requiredStringProperty(wellKnown, "token_endpoint"), requiredStringProperty(wellKnown, "revocation_endpoint"), optionalStringProperty(wellKnown, "registration_endpoint"), + optionalStringProperty(wellKnown, "account_management_uri"), + optionalStringArrayProperty(wellKnown, "account_management_actions_supported"), requiredArrayValue(wellKnown, "response_types_supported", "code"), requiredArrayValue(wellKnown, "grant_types_supported", "authorization_code"), requiredArrayValue(wellKnown, "code_challenge_methods_supported", "S256"), @@ -109,10 +123,12 @@ export const validateOIDCIssuerWellKnown = (wellKnown: unknown): ValidatedIssuer if (!isInvalid) { return { - authorizationEndpoint: wellKnown["authorization_endpoint"], - tokenEndpoint: wellKnown["token_endpoint"], - registrationEndpoint: wellKnown["registration_endpoint"], - } as ValidatedIssuerConfig; + authorizationEndpoint: wellKnown["authorization_endpoint"], + tokenEndpoint: wellKnown["token_endpoint"], + registrationEndpoint: wellKnown["registration_endpoint"], + accountManagementEndpoint: wellKnown["account_management_uri"], + accountManagementActionsSupported: wellKnown["account_management_actions_supported"], + }; } logger.error("Issuer configuration not valid");