-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
refactor (plus fixes): rewrite auth logic for simplification #7
Changes from all commits
1f5d2b1
f819ded
24c22ad
29e3d96
fe93971
7af7dce
63fc0a8
aa6f288
f025128
ec7e97a
d8fe427
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,19 +1,32 @@ | ||
# Required for Administration API tutorial, to acquire auth tokens | ||
# See https://docs.camunda.io/docs/apis-tools/administration-api/authentication/#client-credentials-and-scopes | ||
# Shared by various API tutorials | ||
CLUSTER_ID=fill-this-in | ||
|
||
------------------------------------ | ||
|
||
# Administration API tutorial | ||
|
||
## Capture these values from an API client created at the organization level, with access to the Cluster scope. | ||
## See https://docs.camunda.io/docs/apis-tools/administration-api/authentication/#client-credentials-and-scopes for more details. | ||
### This value comes from the `CAMUNDA_CONSOLE_CLIENT_ID`. | ||
ADMINISTRATION_CLIENT_ID=fill-this-in | ||
### This value comes from the `CAMUNDA_CONSOLE_CLIENT_SECRET`. | ||
ADMINISTRATION_CLIENT_SECRET=fill-this-in | ||
|
||
# Required for Administration API tutorial, to access API | ||
ADMINISTRATION_API_URL=https://api.cloud.camunda.io | ||
## These values will only change if you're not using SaaS. | ||
ADMINISTRATION_AUDIENCE=api.cloud.camunda.io | ||
CLUSTER_ID=fill-this-in | ||
ADMINISTRATION_API_URL=https://api.cloud.camunda.io | ||
|
||
------------------------------------ | ||
|
||
# Required for non-Administration API tutorials, to acquire auth tokens | ||
COMPONENTS_CLIENT_ID=fill-this-in | ||
COMPONENTS_CLIENT_SECRET=fill-this-in | ||
# Optimize API tutorial | ||
|
||
# Required for Optimize API tutorial, to access API | ||
## Capture these values from an API client created at the cluster level, with access to the Optimize scope. | ||
### This value comes from the `ZEEBE_CLIENT_ID`. | ||
OPTIMIZE_CLIENT_ID=fill-this-in | ||
### This value comes from the `ZEEBE_CLIENT_SECRET`. | ||
OPTIMIZE_CLIENT_SECRET=fill-this-in | ||
### This value comes from the `CAMUNDA_OPTIMIZE_BASE_URL`. | ||
OPTIMIZE_BASE_URL=fill-this-in | ||
|
||
## This value will only change if you're not using SaaS. | ||
OPTIMIZE_AUDIENCE=optimize.camunda.io |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,28 +1,40 @@ | ||
import { AuthorizationCode } from "simple-oauth2"; | ||
|
||
const adminConfiguration = { | ||
// These credentials come from your .env file. | ||
clientID: process.env.ADMINISTRATION_CLIENT_ID, | ||
clientSecret: process.env.ADMINISTRATION_CLIENT_SECRET | ||
}; | ||
// This function can be used by callers to retrieve a token prior to their API calls. | ||
/** | ||
* @param {Object} config - A configuration object for authorizing the API client. | ||
* @param {string} config.clientId - The client ID for the API client. | ||
* @param {string} config.clientSecret - The client secret for the API client. | ||
* @param {string} config.audience - The audience associated with the target API. | ||
* @returns {string} | ||
*/ | ||
export async function getAccessToken(config) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I moved this function to the top of the file, because it is the entry point to this logic, and for users who want to read the code and understand how to use a library to handle auth for their code, this is where they'll want to start. It also now takes a |
||
try { | ||
const client = configureAuthorizationClient(config); | ||
const tokenParams = getTokenParams(config); | ||
|
||
const componentConfiguration = { | ||
// These credentials come from your .env file. | ||
clientID: process.env.COMPONENTS_CLIENT_ID, | ||
clientSecret: process.env.COMPONENTS_CLIENT_SECRET | ||
}; | ||
const result = await client.getToken(tokenParams); | ||
const accessToken = client.createToken(result); | ||
|
||
// Configure our authorization request. | ||
function configureAuthorizationClient(targetApi) { | ||
const configSource = | ||
targetApi === "administration" | ||
? adminConfiguration | ||
: componentConfiguration; | ||
// Return the actual token that can be passed as an Authorization header in each request. | ||
return accessToken.token.token.access_token; | ||
} catch (error) { | ||
throw new Error(error.message); | ||
} | ||
} | ||
|
||
// Configure our authorization request. | ||
/** | ||
* @param {Object} config - A configuration object for authorizing the API client. | ||
* @param {string} config.clientId - The client ID for the API client. | ||
* @param {string} config.clientSecret - The client secret for the API client. | ||
* @returns {Object} A configured authorization client. | ||
*/ | ||
function configureAuthorizationClient({ clientId, clientSecret }) { | ||
const config = { | ||
client: { | ||
id: configSource.clientID, | ||
secret: configSource.clientSecret | ||
id: clientId, | ||
secret: clientSecret | ||
}, | ||
auth: { | ||
// This is the URL for our auth server. | ||
|
@@ -36,37 +48,14 @@ function configureAuthorizationClient(targetApi) { | |
} | ||
|
||
// Define additional parameters for the authorization request. | ||
function getTokenParams(audience) { | ||
/** | ||
* @param {Object} config - A configuration object for authorizing the API client. | ||
* @param {string} config.audience - The audience associated with the target API. | ||
* @returns {Object} Token parameters for the authorization request. | ||
*/ | ||
function getTokenParams({ audience }) { | ||
return { | ||
// This audience is specific to the Camunda API we are calling. | ||
audience | ||
}; | ||
} | ||
|
||
// This function can be used by callers to retrieve a token prior to their API calls. | ||
/** | ||
* | ||
* @param {"administration" | "components"} targetApi Use "administration" for only the administration API; "components" for all other component APIs. | ||
* @param {string} audience The `audience` required by the target API. | ||
* @returns | ||
*/ | ||
export async function getAccessToken(targetApi, audience) { | ||
if (targetApi !== "administration" && targetApi !== "components") { | ||
throw new Error( | ||
"Unexpected targetApi value. Expecing 'administration' or 'components'." | ||
); | ||
} | ||
|
||
try { | ||
const client = configureAuthorizationClient(targetApi); | ||
const tokenParams = getTokenParams(audience); | ||
|
||
const result = await client.getToken(tokenParams); | ||
const accessToken = client.createToken(result); | ||
|
||
// Return the actual token that can be passed as an Authorization header in each request. | ||
return accessToken.token.token.access_token; | ||
} catch (error) { | ||
throw new Error(error.message); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,16 @@ | ||
import axios from "axios"; | ||
import { getAccessToken } from "./auth.js"; | ||
|
||
const authorizationConfiguration = { | ||
clientId: process.env.ADMINISTRATION_CLIENT_ID, | ||
clientSecret: process.env.ADMINISTRATION_CLIENT_SECRET, | ||
audience: process.env.ADMINISTRATION_AUDIENCE | ||
}; | ||
Comment on lines
+4
to
+8
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I like the idea of assigning this config object once per API client, rather than every single time. Open to feedback on it though. |
||
|
||
// An action that lists all clients. | ||
async function listClients() { | ||
const administrationAudience = process.env.ADMINISTRATION_AUDIENCE; | ||
|
||
// Every request needs an access token. | ||
const accessToken = await getAccessToken( | ||
"administration", | ||
administrationAudience | ||
); | ||
const accessToken = await getAccessToken(authorizationConfiguration); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this call gets simplified, and a little more clear IMO. |
||
|
||
// These settings come from your .env file. | ||
const administrationApiUrl = process.env.ADMINISTRATION_API_URL; | ||
|
@@ -45,13 +46,8 @@ async function listClients() { | |
|
||
// An action that adds a new client. | ||
async function addClient([clientName]) { | ||
const administrationAudience = process.env.ADMINISTRATION_AUDIENCE; | ||
|
||
// Every request needs an access token. | ||
const accessToken = await getAccessToken( | ||
"administration", | ||
administrationAudience | ||
); | ||
const accessToken = await getAccessToken(authorizationConfiguration); | ||
|
||
// These settings come from your .env file. | ||
const administrationApiUrl = process.env.ADMINISTRATION_API_URL; | ||
|
@@ -95,13 +91,8 @@ async function addClient([clientName]) { | |
|
||
// An action that views one client. | ||
async function viewClient([clientId]) { | ||
const administrationAudience = process.env.ADMINISTRATION_AUDIENCE; | ||
|
||
// Every request needs an access token. | ||
const accessToken = await getAccessToken( | ||
"administration", | ||
administrationAudience | ||
); | ||
const accessToken = await getAccessToken(authorizationConfiguration); | ||
|
||
// These settings come from your .env file. | ||
const administrationApiUrl = process.env.ADMINISTRATION_API_URL; | ||
|
@@ -136,13 +127,8 @@ async function viewClient([clientId]) { | |
|
||
// An action that deletes a client. | ||
async function deleteClient([clientId]) { | ||
const administrationAudience = process.env.ADMINISTRATION_AUDIENCE; | ||
|
||
// Every request needs an access token. | ||
const accessToken = await getAccessToken( | ||
"administration", | ||
administrationAudience | ||
); | ||
const accessToken = await getAccessToken(authorizationConfiguration); | ||
|
||
// These settings come from your .env file. | ||
const administrationApiUrl = process.env.ADMINISTRATION_API_URL; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,14 @@ | ||
import axios from "axios"; | ||
import { getAccessToken } from "./auth.js"; | ||
|
||
const authorizationConfiguration = { | ||
clientId: process.env.OPTIMIZE_CLIENT_ID, | ||
clientSecret: process.env.OPTIMIZE_CLIENT_SECRET, | ||
audience: process.env.OPTIMIZE_AUDIENCE | ||
}; | ||
|
||
async function listDashboards([collectionId]) { | ||
const optimizeAudience = process.env.OPTIMIZE_AUDIENCE; | ||
const accessToken = await getAccessToken("components", optimizeAudience); | ||
const accessToken = await getAccessToken(authorizationConfiguration); | ||
|
||
const optimizeApiUrl = process.env.OPTIMIZE_BASE_URL; | ||
// This is the API endpoint to list your existing dashboard IDs | ||
|
@@ -33,11 +38,10 @@ async function listDashboards([collectionId]) { | |
async function deleteDashboard([dashboardId]) { | ||
console.log(`deleting dashboard ${dashboardId}`); | ||
|
||
const optimizeAudience = process.env.OPTIMIZE_AUDIENCE; | ||
const accessToken = await getAccessToken("components", optimizeAudience); | ||
const optimizeApiUrl = process.env.OPTIMIZE_API_URL; | ||
const accessToken = await getAccessToken(authorizationConfiguration); | ||
|
||
const url = `${optimizeApiUrl}/public/dashboard/${dashboardId}`; | ||
const optimizeApiUrl = process.env.OPTIMIZE_BASE_URL; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bug here: the key name didn't match what's in our .env.example, or the other client function ( |
||
const url = `${optimizeApiUrl}/api/public/dashboard/${dashboardId}`; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bug here: the |
||
|
||
// Configure the API call. | ||
const options = { | ||
|
@@ -55,7 +59,7 @@ async function deleteDashboard([dashboardId]) { | |
|
||
// Process the results from the API call. | ||
if (response.status === 204) { | ||
console.log(`Dashboard ${clientId} was deleted!`); | ||
console.log(`Dashboard ${dashboardId} was deleted!`); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bug here: |
||
} else { | ||
// Emit an unexpected error message. | ||
console.error("Unable to delete dashboard!"); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I reordered keys in this file to better associate them with each other.