diff --git a/db/knex_migrations/2025-06-24-0000-add-audience-to-oauth.js b/db/knex_migrations/2025-06-24-0000-add-audience-to-oauth.js new file mode 100644 index 000000000..6666ed9c8 --- /dev/null +++ b/db/knex_migrations/2025-06-24-0000-add-audience-to-oauth.js @@ -0,0 +1,12 @@ +exports.up = function (knex) { + return knex.schema + .alterTable("monitor", function (table) { + table.string("oauth_audience").nullable().defaultTo(null); + }); +}; + +exports.down = function (knex) { + return knex.schema.alterTable("monitor", function (table) { + table.string("oauth_audience").alter(); + }); +}; diff --git a/server/model/monitor.js b/server/model/monitor.js index c1db77e8b..3be8267c9 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -181,6 +181,7 @@ class Monitor extends BeanModel { oauth_client_secret: this.oauth_client_secret, oauth_token_url: this.oauth_token_url, oauth_scopes: this.oauth_scopes, + oauth_audience: this.oauth_audience, oauth_auth_method: this.oauth_auth_method, pushToken: this.pushToken, databaseConnectionString: this.databaseConnectionString, @@ -1746,7 +1747,7 @@ class Monitor extends BeanModel { */ async makeOidcTokenClientCredentialsRequest() { log.debug("monitor", `[${this.name}] The oauth access-token undefined or expired. Requesting a new token`); - const oAuthAccessToken = await getOidcTokenClientCredentials(this.oauth_token_url, this.oauth_client_id, this.oauth_client_secret, this.oauth_scopes, this.oauth_auth_method); + const oAuthAccessToken = await getOidcTokenClientCredentials(this.oauth_token_url, this.oauth_client_id, this.oauth_client_secret, this.oauth_scopes, this.oauth_audience, this.oauth_auth_method); if (this.oauthAccessToken?.expires_at) { log.debug("monitor", `[${this.name}] Obtained oauth access-token. Expires at ${new Date(this.oauthAccessToken?.expires_at * 1000)}`); } else { diff --git a/server/server.js b/server/server.js index 5b2f41a2e..b7025464b 100644 --- a/server/server.js +++ b/server/server.js @@ -802,6 +802,7 @@ let needSetup = false; bean.oauth_auth_method = monitor.oauth_auth_method; bean.oauth_token_url = monitor.oauth_token_url; bean.oauth_scopes = monitor.oauth_scopes; + bean.oauth_audience = monitor.oauth_audience; bean.tlsCa = monitor.tlsCa; bean.tlsCert = monitor.tlsCert; bean.tlsKey = monitor.tlsKey; diff --git a/server/util-server.js b/server/util-server.js index 4da4be91b..d4a37970d 100644 --- a/server/util-server.js +++ b/server/util-server.js @@ -58,7 +58,7 @@ exports.initJWTSecret = async () => { }; /** - * Decodes a jwt and returns the payload portion without verifying the jqt. + * Decodes a jwt and returns the payload portion without verifying the jwt. * @param {string} jwt The input jwt as a string * @returns {object} Decoded jwt payload object */ @@ -67,15 +67,16 @@ exports.decodeJwt = (jwt) => { }; /** - * Gets a Access Token form a oidc/oauth2 provider - * @param {string} tokenEndpoint The token URI form the auth service provider + * Gets an Access Token from an oidc/oauth2 provider + * @param {string} tokenEndpoint The token URI from the auth service provider * @param {string} clientId The oidc/oauth application client id * @param {string} clientSecret The oidc/oauth application client secret - * @param {string} scope The scope the for which the token should be issued for - * @param {string} authMethod The method on how to sent the credentials. Default client_secret_basic + * @param {string} scope The scope(s) for which the token should be issued for + * @param {string} audience The audience for which the token should be issued for + * @param {string} authMethod The method used to send the credentials. Default client_secret_basic * @returns {Promise} TokenSet promise if the token request was successful */ -exports.getOidcTokenClientCredentials = async (tokenEndpoint, clientId, clientSecret, scope, authMethod = "client_secret_basic") => { +exports.getOidcTokenClientCredentials = async (tokenEndpoint, clientId, clientSecret, scope, audience, authMethod = "client_secret_basic") => { const oauthProvider = new oidc.Issuer({ token_endpoint: tokenEndpoint }); let client = new oauthProvider.Client({ client_id: clientId, @@ -91,6 +92,10 @@ exports.getOidcTokenClientCredentials = async (tokenEndpoint, clientId, clientSe if (scope) { grantParams.scope = scope; } + + if (audience) { + grantParams.audience = audience; + } return await client.grant(grantParams); }; diff --git a/src/lang/en.json b/src/lang/en.json index a979edcc2..b6449371b 100644 --- a/src/lang/en.json +++ b/src/lang/en.json @@ -1022,6 +1022,8 @@ "Client ID": "Client ID", "Client Secret": "Client Secret", "OAuth Scope": "OAuth Scope", + "OAuth Audience": "OAuth Audience", + "Optional: The audience to request the JWT for": "Optional: The audience to request the JWT for", "Optional: Space separated list of scopes": "Optional: Space separated list of scopes", "Go back to home page.": "Go back to home page.", "No tags found.": "No tags found.", diff --git a/src/pages/EditMonitor.vue b/src/pages/EditMonitor.vue index 0d628895d..1b7af4184 100644 --- a/src/pages/EditMonitor.vue +++ b/src/pages/EditMonitor.vue @@ -1025,6 +1025,10 @@ +
+ + +