Skip to content
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

Merged
merged 11 commits into from
May 28, 2024

Conversation

pepopowitz
Copy link
Collaborator

@pepopowitz pepopowitz commented May 10, 2024

[BLOCKED]: requires additional changes outside this PR to be merged at roughly the same time.


This PR rewrites the auth logic in our API tutorials, to simplify the logic, and to make it more clear to readers how the client ID, secret, and audience are used for authorization.

It also fixes a couple bugs in the Optimize API client code. I'll call these out with inline comments. I'm open to the idea that these bugs should be fixed in a separate PR, so that they don't have to wait for this and its related PRs (described in "Outside impact") to land.

Outside impact

There are multiple points of impact outside this PR:

  1. ✅ Our associated API tutorial docs will need to be updated to account for these changes. (Christina has done this in Create optimize api tutorial and revise admin api tutorial camunda-docs#3708!)
  2. Create modeler api tutorial #5 will need to be updated with the new approach to authorization. (this can happen in a follow-up PR, because Create modeler api tutorial #5 is still in progress.)

Why are we rewriting the auth logic again?

While walking through #5, and reading comments there, I realized that the reusability I've been trying to accomplish in the auth logic contains an abstraction that is confusing, and also adds complexity to the auth.js logic that distracts readers from understanding how their code acquires authorization tokens.

This new approach to auth removes the abstraction ("administration" APIs vs "component" APIs) in favor of requiring the calling client to pass in its own client ID, secret, and audience. This makes it easier to read the auth.js code, and it makes it more obvious that those three bits are required to authorize an API client.

@pepopowitz pepopowitz added bug Something isn't working enhancement New feature or request labels May 10, 2024
@pepopowitz pepopowitz self-assigned this May 10, 2024
Copy link
Collaborator Author

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.

.env.example Outdated
Comment on lines 14 to 17
# Required for Optimize API tutorials, to acquire auth tokens
OPTIMIZE_CLIENT_ID=fill-this-in
OPTIMIZE_CLIENT_SECRET=fill-this-in
OPTIMIZE_AUDIENCE=optimize.camunda.io
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These keys are now specific to the Optimize API only. There will be no shared use of these keys across other "component" APIs.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I get hung up here if I put on my super novice user hat. If I download my credentials as environment variables, I get values that look like this:

export ZEEBE_ADDRESS='xx.zeebe.camunda.io:443'
export ZEEBE_CLIENT_ID='xx'
export ZEEBE_CLIENT_SECRET=xx'
export ZEEBE_AUTHORIZATION_SERVER_URL='https://login.cloud.camunda.io/oauth/token'
export ZEEBE_REST_ADDRESS='https://lhr-1.zeebe.camunda.io/xx'
export ZEEBE_GRPC_ADDRESS='grpcs://xx-1.zeebe.camunda.io:443'
export ZEEBE_TOKEN_AUDIENCE='zeebe.camunda.io'
export CAMUNDA_CLUSTER_ID='xx'
export CAMUNDA_CLUSTER_REGION='lhr-1'
export CAMUNDA_CREDENTIALS_SCOPES='Zeebe,Tasklist,Operate,Optimize,Secrets'
export CAMUNDA_TASKLIST_BASE_URL='https://lhr-1.tasklist.camunda.io/xx'
export CAMUNDA_OPTIMIZE_BASE_URL='https://lhr-1.optimize.camunda.io/xx'
export CAMUNDA_OPERATE_BASE_URL='https://lhr-1.operate.camunda.io/xx'
export CAMUNDA_OAUTH_URL='https://login.cloud.camunda.io/oauth/token'

Zeebe is the only component that shows a CLIENT_ID and CLIENT_SECRET. This remains true even if the scope is only Optimize.

Do you think this is confusing or misleading?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe but I'm not sure how to address the fact that client IDs/secrets can be used across multiple APIs, but they don't have to be, and some of them come from the organization level and others come from the cluster level. Supporting the re-use of credentials across multiple APIs seems to provide multiple points of confusion; assigning one secret/key per API in the environment variables still allows for people to reuse credentials, if they want, but also makes it obvious that they need creds that will work for that specific API.

Do you have any suggestions? Can this be addressed in the supporting tutorial?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the .env.example file, I would note what values you will expect to see in the downloaded credentials. So, in this case, I needed to use the ZEEBE_CLIENT_ID as the OPTIMIZE_CLIENT_ID, etc. You can also note this in the docs with an admonition.

I would encourage you or Christina to follow up with the Console team because this looks misleading. I don't think these values are specific to Zeebe but old historical artifacts from a time when there were only Zeebe clients.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this what you're looking for?

image

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I think this is super helpful and something we should keep an eye on in case there is confusion around where to get these values. Thank you!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pepopowitz were you going to add these changes to this PR? I'm on the fence about whether this is blocking or not.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought I had! I just pushed these changes.

* @param {string} config.audience - The audience associated with the target API.
* @returns {string}
*/
export async function getAccessToken(config) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The 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 config object, which contains three properties: clientId, clientSecret, and audience. Previously we were passing a magic string and doing some lookups within this file to get the correct environment variables, but that was obfuscating important details -- you need the client id, secret, and audience in order to authorize.

Comment on lines +4 to +8
const authorizationConfiguration = {
clientId: process.env.ADMINISTRATION_CLIENT_ID,
clientSecret: process.env.ADMINISTRATION_CLIENT_SECRET,
audience: process.env.ADMINISTRATION_AUDIENCE
};
Copy link
Collaborator Author

Choose a reason for hiding this comment

The 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.

"administration",
administrationAudience
);
const accessToken = await getAccessToken(authorizationConfiguration);
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this call gets simplified, and a little more clear IMO.


const url = `${optimizeApiUrl}/public/dashboard/${dashboardId}`;
const optimizeApiUrl = process.env.OPTIMIZE_BASE_URL;
Copy link
Collaborator Author

Choose a reason for hiding this comment

The 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 (listDashboards).


const url = `${optimizeApiUrl}/public/dashboard/${dashboardId}`;
const optimizeApiUrl = process.env.OPTIMIZE_BASE_URL;
const url = `${optimizeApiUrl}/api/public/dashboard/${dashboardId}`;
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug here: the /api was missing at the beginning, resulting in a failed API call.

@@ -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!`);
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug here: clientId was copy-pasta, and this line was throwing an undefined variable error.

Copy link
Member

@akeller akeller left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Went through this for Optimize and it works!

@pepopowitz pepopowitz changed the title [BLOCKED] refactor (plus fixes): rewrite auth logic for simplification refactor (plus fixes): rewrite auth logic for simplification May 20, 2024
@pepopowitz pepopowitz merged commit 81b3f5e into main May 28, 2024
1 check passed
@pepopowitz pepopowitz deleted the pepopowitz/rewrite-auth-again branch May 28, 2024 20:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working enhancement New feature or request
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

2 participants