node-mongodb-native icon indicating copy to clipboard operation
node-mongodb-native copied to clipboard

feat(NODE-5464): OIDC machine and callback workflow

Open durran opened this issue 1 year ago • 4 comments

Description

Implements OIDC new machine and human callback workflows.

What is changing?

  • Implements the OIDC callback workflow. Specified with OIDC_CALLBACK auth mech property.
  • Implements the OIDC human callback workflow. Specified with OIDC_HUMAN_CALLBACK auth mech property.
  • Implements the OIDC Test machine workflow. Specified with ENVIRONMENT:test auth mech property.
  • Implements the OIDC Azure machine workflow. Specified with ENVIRONMENT:azure auth mech property.
  • Implements the OIDC GCP machine workflow. Specified with ENVIRONMENT:gcp auth mech property.
  • Uses a new generic TokenCache for all OIDC authentication that sits at the auth provider level.
  • Removes the old complex callback workflow global caching.
  • Removes the old global Azure token cache.
Is there new documentation needed for these changes?

What is the motivation for this change?

https://github.com/mongodb/specifications/pull/1471 https://github.com/mongodb/specifications/pull/1544 https://github.com/mongodb/specifications/pull/1513

Release Highlight

Support for MONGODB-OIDC Authentication

MONGODB-OIDC is now supported as an authentication mechanism for MongoDB server versions 7.0+. The currently supported facets to authenticate with are callback authentication, human interaction callback authentication, Azure machine authentication, and GCP machine authentication.

Azure Machine Authentication

The MongoClient must be instantiated with authMechanism=MONGODB-OIDC in the URI or in the client options. Additional required auth mechanism properties of TOKEN_RESOURCE and ENVIRONMENT are required and another optional username can be provided. Example:

const client = new MongoClient('mongodb+srv://<username>@<host>:<port>/?authMechanism=MONGODB-OIDC&authMechanismProperties=TOKEN_RESOURCE:<azure_token>,ENVIRONMENT=azure');
await client.connect();

GCP Machine Authentication

The MongoClient must be instantiated with authMechanism=MONGODB-OIDC in the URI or in the client options. Additional required auth mechanism properties of TOKEN_RESOURCE and ENVIRONMENT are required. Example:

const client = new MongoClient('mongodb+srv://<host>:<port>/?authMechanism=MONGODB-OIDC&authMechanismProperties=TOKEN_RESOURCE:<gcp_token>,ENVIRONMENT=gcp');
await client.connect();

Callback Authentication

The user can provide a custom callback to the MongoClient that returns a valid response with an access token. The callback is provided as an auth mechanism property an has the signature of:

const oidcCallBack = (params: OIDCCallbackParams): Promise<OIDCResponse> => {
  // params.timeoutContext is an AbortSignal that will abort after 30 seconds for non-human and 5 minutes for human.
  // params.version is the current OIDC API version.
  // params.idpInfo is the IdP info returned from the server.
  // params.username is the optional username.

  // Make a call to get a token.
  const token = ...;
  return {
     accessToken: token,
     expiresInSeconds: 300,
     refreshToken: token
  };
}

const client = new MongoClient('mongodb+srv://<host>:<port>/?authMechanism=MONGODB-OIDC', {
  authMechanismProperties: {
    OIDC_CALLBACK: oidcCallback
  }
});
await client.connect();

For callbacks that require human interaction, set the callback to the OIDC_HUMAN_CALLBACK property:

const client = new MongoClient('mongodb+srv://<host>:<port>/?authMechanism=MONGODB-OIDC', {
  authMechanismProperties: {
    OIDC_HUMAAN_CALLBACK: oidcCallback
  }
});
await client.connect();

Double check the following

  • [x] Ran npm run check:lint script
  • [x] Self-review completed using the steps outlined here
  • [x] PR title follows the correct format: type(NODE-xxxx)[!]: description
    • Example: feat(NODE-1234)!: rewriting everything in coffeescript
  • [x] Changes are covered by tests
  • [ ] New TODOs have a related JIRA ticket

durran avatar Nov 07 '23 18:11 durran

@blink1073 Is there ever a divergence between connection level and client level caching?

I can't find where to respond. Yes, if another connection on the same client has already re-authenticated, we see that the client cache is different (or newer) than the connection cache, and use that instead.

blink1073 avatar May 06 '24 16:05 blink1073

@blink1073 Is there ever a divergence between connection level and client level caching?

I can't find where to respond. Yes, if another connection on the same client has already re-authenticated, we see that the client cache is different (or newer) than the connection cache, and use that instead.

@blink1073 I'm just curious as to what the point of the connection cache is at all? If the client cache is always the source of truth for all connections, isn't it simpler just to always use that and not copy tokens down to all the connections and need to check their values against the client cache?

durran avatar May 06 '24 19:05 durran

@blink1073 I'm just curious as to what the point of the connection cache is at all? If the client cache is always the source of truth for all connections, isn't it simpler just to always use that and not copy tokens down to all the connections and need to check their values against the client cache?

It allows us to figure out how to handle a 391 error, whether we actually need to call the callback again. If we get our 391 after another connection, then it would have already updated the client cache, making it different/newer than the connection cache.

blink1073 avatar May 06 '24 20:05 blink1073

https://github.com/mongodb/node-mongodb-native/pull/3912#discussion_r1598862353

I've update to export both TokenCache and Workflow as types.

durran avatar May 14 '24 15:05 durran