Created
August 25, 2023 21:02
-
-
Save tsibley/671d6be0df6539751a386306e37fd7eb to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/aws/cognito/outputs.tf b/aws/cognito/outputs.tf | |
index db9e9c0d..3e7f55d2 100644 | |
--- a/aws/cognito/outputs.tf | |
+++ b/aws/cognito/outputs.tf | |
@@ -2,6 +2,7 @@ output "COGNITO_USER_POOL_ID" { | |
value = aws_cognito_user_pool.nextstrain_dot_org.id | |
} | |
+# XXX FIXME | |
output "COGNITO_BASE_URL" { | |
value = format("https://%s", coalesce( | |
one(aws_cognito_user_pool_domain.custom[*].domain), | |
@@ -9,10 +10,12 @@ output "COGNITO_BASE_URL" { | |
)) | |
} | |
+# XXX FIXME | |
output "COGNITO_CLIENT_ID" { | |
value = aws_cognito_user_pool_client.nextstrain_dot_org.id | |
} | |
+# XXX FIXME | |
output "COGNITO_CLI_CLIENT_ID" { | |
value = aws_cognito_user_pool_client.nextstrain-cli.id | |
} | |
diff --git a/docs/infrastructure.md b/docs/infrastructure.md | |
index e7fa6b5f..a0df718b 100644 | |
--- a/docs/infrastructure.md | |
+++ b/docs/infrastructure.md | |
@@ -72,12 +72,18 @@ Several variables are required but obtain defaults from a config file (e.g. `env | |
- `COGNITO_USER_POOL_ID` must be set to the id of the Cognito user pool to use for authentication. | |
+XXX FIXME | |
+ | |
- `COGNITO_BASE_URL` must be set to the URL of the Cognito user pool's hosted UI. | |
In production, this is `https://login.nextstrain.org`. | |
In development and testing, this would be something like `https://nextstrain-testing.auth.us-east-1.amazoncognito.com`. | |
+XXX FIXME | |
+ | |
- `COGNITO_CLIENT_ID` must be set to the OAuth2 client id for the nextstrain.org client registered with the Cognito user pool. | |
+XXX FIXME | |
+ | |
- `COGNITO_CLI_CLIENT_ID` must be set to the OAuth2 client id for the Nextstrain CLI client registered with the Cognito user pool. | |
Variables in the environment override defaults from the config file. | |
diff --git a/docs/terraform.rst b/docs/terraform.rst | |
index 312d332e..ae54de81 100644 | |
--- a/docs/terraform.rst | |
+++ b/docs/terraform.rst | |
@@ -261,6 +261,8 @@ Outputs | |
Each configuration provides outputs of key-value pairs corresponding to | |
environment (or config) variables required by the nextstrain.org server:: | |
+.. XXX FIXME | |
+ | |
$ terraform output | |
COGNITO_BASE_URL=https://login.nextstrain.org | |
COGNITO_CLIENT_ID=rki99ml8g2jb9sm1qcq9oi5n | |
diff --git a/env/outputs.tf b/env/outputs.tf | |
index 9d50c1a0..f80cfedc 100644 | |
--- a/env/outputs.tf | |
+++ b/env/outputs.tf | |
@@ -6,14 +6,17 @@ output "COGNITO_USER_POOL_ID" { | |
value = module.cognito.COGNITO_USER_POOL_ID | |
} | |
+# XXX FIXME | |
output "COGNITO_BASE_URL" { | |
value = module.cognito.COGNITO_BASE_URL | |
} | |
+# XXX FIXME | |
output "COGNITO_CLIENT_ID" { | |
value = module.cognito.COGNITO_CLIENT_ID | |
} | |
+# XXX FIXME | |
output "COGNITO_CLI_CLIENT_ID" { | |
value = module.cognito.COGNITO_CLI_CLIENT_ID | |
} | |
diff --git a/env/production/config.json b/env/production/config.json | |
index d4da4ce9..512efdb4 100644 | |
--- a/env/production/config.json | |
+++ b/env/production/config.json | |
@@ -1,6 +1,7 @@ | |
{ | |
- "COGNITO_BASE_URL": "https://login.nextstrain.org", | |
- "COGNITO_CLIENT_ID": "rki99ml8g2jb9sm1qcq9oi5n", | |
- "COGNITO_CLI_CLIENT_ID": "2vmc93kj4fiul8uv40uqge93m5", | |
+ "OIDC_IDP_URL": "https://cognito-idp.us-east-1.amazonaws.com/us-east-1_Cg5rcTged", | |
+ "OAUTH2_CLIENT_ID": "rki99ml8g2jb9sm1qcq9oi5n", | |
+ "OAUTH2_CLI_CLIENT_ID": "2vmc93kj4fiul8uv40uqge93m5", | |
+ "OAUTH2_LOGOUT_URL": "https://login.nextstrain.org/logout", | |
"COGNITO_USER_POOL_ID": "us-east-1_Cg5rcTged" | |
} | |
diff --git a/env/testing-ad/config.json b/env/testing-ad/config.json | |
new file mode 100644 | |
index 00000000..e0327c18 | |
--- /dev/null | |
+++ b/env/testing-ad/config.json | |
@@ -0,0 +1,9 @@ | |
+{ | |
+ "OIDC_IDP_URL": "https://login.microsoftonline.com/0ce9e8dc-e009-4cb4-8512-7989bd6906a8/v2.0", | |
+ "OAUTH2_CLIENT_ID": "c3d6647f-dccc-4a85-a2bb-fb8fbc7524a9", | |
+ "OAUTH2_CLIENT_SECRET": "jdn8Q~van5hyY2-MGBa1gzapqnPYEHrGcGaCfa70", | |
+ "OAUTH2_CLI_CLIENT_ID": "BOGUS", | |
+ "OIDC_USERNAME_CLAIM": "preferred_username", | |
+ "OIDC_GROUPS_CLAIM": "groups", | |
+ "COGNITO_USER_POOL_ID": "us-east-1_zqpCrjM7I" | |
+} | |
diff --git a/env/testing/config.json b/env/testing/config.json | |
index 6ce4d2a8..a76ac1ae 100644 | |
--- a/env/testing/config.json | |
+++ b/env/testing/config.json | |
@@ -1,6 +1,7 @@ | |
{ | |
- "COGNITO_BASE_URL": "https://nextstrain-testing.auth.us-east-1.amazoncognito.com", | |
- "COGNITO_CLIENT_ID": "6qiojrhr8tibt0f6hphnm1osp1", | |
- "COGNITO_CLI_CLIENT_ID": "9opa27o74f4jsq8g4a34e1mqr", | |
+ "OIDC_IDP_URL": "https://cognito-idp.us-east-1.amazonaws.com/us-east-1_zqpCrjM7I", | |
+ "OAUTH2_CLIENT_ID": "6qiojrhr8tibt0f6hphnm1osp1", | |
+ "OAUTH2_CLI_CLIENT_ID": "9opa27o74f4jsq8g4a34e1mqr", | |
+ "OAUTH2_LOGOUT_URL": "https://nextstrain-testing.auth.us-east-1.amazoncognito.com/logout", | |
"COGNITO_USER_POOL_ID": "us-east-1_zqpCrjM7I" | |
} | |
diff --git a/notes b/notes | |
new file mode 100644 | |
index 00000000..1b9bed4a | |
--- /dev/null | |
+++ b/notes | |
@@ -0,0 +1 @@ | |
+https://www.cedarpolicy.com/en | |
diff --git a/src/authn/index.js b/src/authn/index.js | |
index 3f040ae3..a4a3afa3 100644 | |
--- a/src/authn/index.js | |
+++ b/src/authn/index.js | |
@@ -19,7 +19,7 @@ import { JOSEError, JWTClaimValidationFailed, JWTExpired } from 'jose/util/error | |
import partition from 'lodash.partition'; | |
import BearerStrategy from './bearer.js'; | |
import { getTokens, setTokens, deleteTokens } from './session.js'; | |
-import { PRODUCTION, COGNITO_USER_POOL_ID, COGNITO_BASE_URL, COGNITO_CLIENT_ID, COGNITO_CLI_CLIENT_ID } from '../config.js'; | |
+import { PRODUCTION, OIDC_ISSUER_URL, OIDC_JWKS_URL, OAUTH2_AUTHORIZATION_URL, OAUTH2_TOKEN_URL, OAUTH2_LOGOUT_URL, OAUTH2_SCOPES_SUPPORTED, OIDC_USERNAME_CLAIM, OIDC_GROUPS_CLAIM, OAUTH2_CLIENT_ID, OAUTH2_CLIENT_SECRET, OAUTH2_CLI_CLIENT_ID } from '../config.js'; | |
import { AuthnRefreshTokenInvalid, AuthnTokenTooOld } from '../exceptions.js'; | |
import { fetch } from '../fetch.js'; | |
import { copyCookie } from '../middleware.js'; | |
@@ -56,11 +56,23 @@ const SESSION_SECRET = PRODUCTION | |
const SESSION_MAX_AGE = 30 * 24 * 60 * 60; // 30d in seconds | |
-const COGNITO_REGION = COGNITO_USER_POOL_ID.split("_")[0]; | |
+const OIDC_JWKS = createRemoteJWKSet(new URL(OIDC_JWKS_URL)); | |
-const COGNITO_USER_POOL_URL = `https://cognito-idp.${COGNITO_REGION}.amazonaws.com/${COGNITO_USER_POOL_ID}`; | |
+// These are all scopes defined by OpenID Connect. | |
+const requiredScopes = ["openid", "profile"]; | |
+const optionalScopes = ["email", "offline_access"]; | |
+ | |
+const missingScopes = requiredScopes.filter(s => !OAUTH2_SCOPES_SUPPORTED.has(s)); | |
+if (missingScopes.length) { | |
+ throw new Error(`OAuth2 IdP does not advertise support for the required scopes: ${Array.from(missingScopes).join(" ")}`); | |
+} | |
+ | |
+// XXX FIXME: consider requesting all scopes?? this is the Cognito default, more or less. | |
+const OAUTH2_SCOPES = [ | |
+ ...requiredScopes, | |
+ ...optionalScopes.filter(s => OAUTH2_SCOPES_SUPPORTED.has(s)), | |
+]; | |
-const COGNITO_JWKS = createRemoteJWKSet(new URL(`${COGNITO_USER_POOL_URL}/.well-known/jwks.json`)); | |
/* Registered clients to accept for Bearer tokens. | |
* | |
@@ -68,8 +80,8 @@ const COGNITO_JWKS = createRemoteJWKSet(new URL(`${COGNITO_USER_POOL_URL}/.well- | |
* server start and might want to if we start having third-party clients, but | |
* avoid a start-time dep for now. | |
*/ | |
-const BEARER_COGNITO_CLIENT_IDS = [ | |
- COGNITO_CLI_CLIENT_ID, // Nextstrain CLI | |
+const BEARER_OAUTH2_CLIENT_IDS = [ | |
+ OAUTH2_CLI_CLIENT_ID, // Nextstrain CLI | |
]; | |
/* Arbitrary ids for the various strategies for Passport. Makes explicit the | |
@@ -91,10 +103,12 @@ function setup(app) { | |
STRATEGY_OAUTH2, | |
new OAuth2Strategy( | |
{ | |
- authorizationURL: `${COGNITO_BASE_URL}/oauth2/authorize`, | |
- tokenURL: `${COGNITO_BASE_URL}/oauth2/token`, | |
- clientID: COGNITO_CLIENT_ID, | |
+ authorizationURL: OAUTH2_AUTHORIZATION_URL, | |
+ tokenURL: OAUTH2_TOKEN_URL, | |
+ clientID: OAUTH2_CLIENT_ID, | |
callbackURL: "/logged-in", | |
+ scope: OAUTH2_SCOPES, | |
+ clientSecret: OAUTH2_CLIENT_SECRET, | |
pkce: true, | |
state: true, | |
passReqToCallback: true, | |
@@ -110,9 +124,7 @@ function setup(app) { | |
// All users are ok, as we control the entire user pool. | |
return done(null, user); | |
} catch (e) { | |
- return e instanceof JOSEError | |
- ? done(null, false, "Error verifying token") | |
- : done(e); | |
+ return done(e); | |
} | |
} | |
) | |
@@ -127,7 +139,7 @@ function setup(app) { | |
}, | |
async (idToken, done) => { | |
try { | |
- const user = await userFromIdToken(idToken, BEARER_COGNITO_CLIENT_IDS); | |
+ const user = await userFromIdToken(idToken, BEARER_OAUTH2_CLIENT_IDS); | |
return done(null, user); | |
} catch (e) { | |
if (e instanceof JOSEError) { | |
@@ -433,10 +445,10 @@ function setup(app) { | |
app.route("/logout").get((req, res) => { | |
req.session.destroy(() => { | |
const params = { | |
- client_id: COGNITO_CLIENT_ID, | |
+ client_id: OAUTH2_CLIENT_ID, | |
logout_uri: req.context.origin | |
}; | |
- res.redirect(`${COGNITO_BASE_URL}/logout?${querystring.stringify(params)}`); | |
+ res.redirect(`${OAUTH2_LOGOUT_URL}?${querystring.stringify(params)}`); | |
}); | |
}); | |
} | |
@@ -514,7 +526,7 @@ function authnWithSession(req, res, next) { | |
* @param {String} idToken | |
* @param {String} accessToken | |
* @param {String} refreshToken | |
- * @param {String|String[]} client. Optional. Passed to `verifyToken()`. | |
+ * @param {String|String[]} client. Optional. Passed to `verifyIdToken()`. | |
* @returns {User} User record with e.g. `username` and `groups` keys. | |
*/ | |
async function userFromTokens({idToken, accessToken, refreshToken}, client = undefined) { | |
@@ -526,7 +538,7 @@ async function userFromTokens({idToken, accessToken, refreshToken}, client = und | |
* identity token (which is its intended purpose). Note that refresh tokens | |
* are opaque blobs not subject to verification. | |
*/ | |
- await verifyToken(accessToken, "access", client); | |
+ // XXX FIXME just treat accessToken as opaque?!?!?! | |
// Verifies idToken | |
return await userFromIdToken(idToken, client); | |
@@ -537,16 +549,16 @@ async function userFromTokens({idToken, accessToken, refreshToken}, client = und | |
* Creates a user record from the given `idToken` after verifying it. | |
* | |
* @param {String} idToken | |
- * @param {String|String[]} client. Optional. Passed to `verifyToken()`. | |
+ * @param {String|String[]} client. Optional. Passed to `verifyIdToken()`. | |
* @returns {User} User record with e.g. `username` and `groups` keys. | |
*/ | |
async function userFromIdToken(idToken, client = undefined) { | |
- const idClaims = await verifyToken(idToken, "id", client); | |
+ const idClaims = await verifyIdToken(idToken, client); | |
- const {groups, authzRoles, flags, cognitoGroups} = parseCognitoGroups(idClaims["cognito:groups"] || []); | |
+ const {groups, authzRoles, flags, cognitoGroups} = parseCognitoGroups(idClaims[OIDC_GROUPS_CLAIM] || []); | |
const user = { | |
- username: idClaims["cognito:username"], | |
+ username: idClaims[OIDC_USERNAME_CLAIM], | |
groups, | |
authzRoles, | |
flags, | |
@@ -629,37 +641,36 @@ function splitGroupRole(cognitoGroup) { | |
/** | |
- * Verifies all aspects of the given `token` (a signed JWT from our AWS Cognito | |
- * user pool) which is expected to be used for the given `use`. | |
+ * Verifies all aspects of the given OIDC `idToken` (a signed JWT from our AWS | |
+ * Cognito user pool). | |
* | |
* Assertions about expected algorithms, audience, issuer, and token use follow | |
* guidelines from | |
* <https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-verifying-a-jwt.html>. | |
* | |
- * @param {String} token | |
- * @param {String} use | |
+ * @param {String} idToken | |
* @param {String} client. Optional `client_id` or list of `client_id`s | |
- * expected for the token. Only relevant when `use` is not | |
- * `access`. Defaults to this server's client id. | |
+ * expected for the token. Defaults to this server's client id. | |
* @returns {Object} Verified claims from the token's payload | |
*/ | |
-async function verifyToken(token, use, client = COGNITO_CLIENT_ID) { | |
- const {payload: claims} = await jwtVerify(token, COGNITO_JWKS, { | |
+async function verifyIdToken(idToken, client = OAUTH2_CLIENT_ID) { | |
+ const {payload: claims} = await jwtVerify(idToken, OIDC_JWKS, { | |
algorithms: ["RS256"], | |
- issuer: COGNITO_USER_POOL_URL, | |
- audience: use !== "access" ? client : null, | |
+ issuer: OIDC_ISSUER_URL, | |
+ audience: client, | |
}); | |
+ // XXX FIXME nonstandard Cognito thing | |
const claimedUse = claims["token_use"]; | |
- if (claimedUse !== use) { | |
+ if (claimedUse !== undefined && claimedUse !== "id") { | |
throw new JWTClaimValidationFailed(`unexpected "token_use" claim value: ${claimedUse}`, "token_use", "check_failed"); | |
} | |
/* Verify the token was issued at (iat) a time more recent than our staleness | |
* horizon for the user. | |
*/ | |
- const username = claims[{id: "cognito:username", access: "username"}[claimedUse]]; | |
+ const username = claims[OIDC_USERNAME_CLAIM]; | |
if (!username) { | |
throw new JWTClaimValidationFailed("missing username"); | |
@@ -693,11 +704,16 @@ async function verifyToken(token, use, client = COGNITO_CLIENT_ID) { | |
* except by initiating a new login. | |
*/ | |
async function renewTokens(refreshToken) { | |
- const response = await fetch(`${COGNITO_BASE_URL}/oauth2/token`, { | |
+ const response = await fetch(OAUTH2_TOKEN_URL, { | |
method: "POST", | |
body: new URLSearchParams([ | |
["grant_type", "refresh_token"], | |
- ["client_id", COGNITO_CLIENT_ID], | |
+ ["client_id", OAUTH2_CLIENT_ID], | |
+ ...( | |
+ OAUTH2_CLIENT_SECRET | |
+ ? [["client_secret", OAUTH2_CLIENT_SECRET]] | |
+ : [] | |
+ ), | |
["refresh_token", refreshToken], | |
]), | |
}); | |
diff --git a/src/config.js b/src/config.js | |
index a5272fcb..1d302070 100644 | |
--- a/src/config.js | |
+++ b/src/config.js | |
@@ -10,6 +10,7 @@ | |
* @module config | |
*/ | |
import { readFile } from 'fs/promises'; | |
+import fetch from 'node-fetch'; | |
import path, { dirname } from 'path'; | |
import process from 'process'; | |
import { fileURLToPath } from 'url'; | |
@@ -54,13 +55,16 @@ const configFile = CONFIG_FILE | |
/** | |
* Obtain a configuration variable from the environment or the config file. | |
* | |
+ * Values obtained from the environment will be deserialized from JSON if | |
+ * possible. | |
+ * | |
* @param {string} name - Variable name, e.g. "COGNITO_USER_POOL_ID" | |
* @param {any} default - Final fallback value | |
* @throws {Error} if no value is found and default is undefined | |
*/ | |
const fromEnvOrConfig = (name, default_) => { | |
const value = | |
- process.env[name] | |
+ maybeJSON(process.env[name]) | |
|| configFile?.[name]; | |
if (!value && default_ === undefined) { | |
@@ -70,6 +74,23 @@ const fromEnvOrConfig = (name, default_) => { | |
}; | |
+/** | |
+ * Deserialize a value that might be JSON, passing it thru if it isn't. | |
+ * | |
+ * @param {any} x - Value which might be JSON | |
+ */ | |
+function maybeJSON(x) { | |
+ if (typeof x === "string") { | |
+ try { | |
+ return JSON.parse(x); | |
+ } catch (e) { | |
+ // no worries | |
+ } | |
+ } | |
+ return x; | |
+} | |
+ | |
+ | |
/** | |
* Id of our Cognito user pool. | |
* | |
@@ -81,31 +102,90 @@ export const COGNITO_USER_POOL_ID = fromEnvOrConfig("COGNITO_USER_POOL_ID"); | |
/** | |
- * Base URL (i.e. origin) of our Cognito user pool's hosted UI and OAuth2 | |
- * endpoints. | |
+ * URL of the OIDC IdP for our user directory (e.g. our Cognito user pool's | |
+ * hosted UI and OAuth2 endpoints). | |
* | |
* @type {string} | |
*/ | |
-export const COGNITO_BASE_URL = fromEnvOrConfig("COGNITO_BASE_URL"); | |
+export const OIDC_IDP_URL = fromEnvOrConfig("OIDC_IDP_URL"); | |
/** | |
- * OAuth2 client id of nextstrain.org server as registered with our Cognito | |
- * user pool. | |
+ * OpenID Connect (OIDC) identity provider configuration document. | |
+ * | |
+ * Typically this is unspecified in the environment or config file and instead | |
+ * populated by fetching it from the OIDC IdP. | |
+ * | |
+ * Refer to the spec for the | |
+ * {@link https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata core metadata fields} | |
+ * and the | |
+ * {@link https://www.iana.org/assignments/oauth-parameters/oauth-parameters.xhtml#authorization-server-metadata IANA metadata field registry} | |
+ * for references to other fields. | |
+ * | |
+ * @type {object} | |
+ */ | |
+export const OIDC_CONFIGURATION = fromEnvOrConfig("OIDC_CONFIGURATION", await oidcConfiguration(OIDC_IDP_URL)); | |
+ | |
+async function oidcConfiguration(idpUrl) { | |
+ const url = `${idpUrl}/.well-known/openid-configuration`; | |
+ const response = await fetch(url); | |
+ | |
+ if (!response.ok) { | |
+ console.warn(`Failed to fetch ${url}: ${response.status} ${response.statusText}: ${await response.text()}`); | |
+ return; | |
+ } | |
+ return await response.json(); | |
+} | |
+ | |
+/** "issuer" metadata field in */ | |
+export const OIDC_ISSUER_URL = fromEnvOrConfig("OIDC_ISSUER_URL", OIDC_CONFIGURATION.issuer); | |
+ | |
+/** "jwks_uri" metadata field in OIDC configuration */ | |
+export const OIDC_JWKS_URL = fromEnvOrConfig("OIDC_JWKS_URL", OIDC_CONFIGURATION.jwks_uri); | |
+ | |
+/** "authorization_endpoint" metadata field in OIDC configuration */ | |
+export const OAUTH2_AUTHORIZATION_URL = fromEnvOrConfig("OAUTH2_AUTHORIZATION_URL", OIDC_CONFIGURATION.authorization_endpoint); | |
+ | |
+/** "token_endpoint" metadata field in OIDC configuration */ | |
+export const OAUTH2_TOKEN_URL = fromEnvOrConfig("OAUTH2_TOKEN_URL", OIDC_CONFIGURATION.token_endpoint); | |
+ | |
+/** "end_session_endpoint" metadata field in OIDC configuration with RP-initiated logout support {@link https://openid.net/specs/openid-connect-rpinitiated-1_0.html#OPMetadata} */ | |
+export const OAUTH2_LOGOUT_URL = fromEnvOrConfig("OAUTH2_LOGOUT_URL", OIDC_CONFIGURATION.end_session_endpoint); | |
+ | |
+/** "scopes_supported" metadata field in OIDC configuration */ | |
+export const OAUTH2_SCOPES_SUPPORTED = new Set(fromEnvOrConfig("OAUTH2_SCOPES_SUPPORTED", OIDC_CONFIGURATION.scopes_supported)); | |
+ | |
+/** XXX FIXME */ | |
+export const OIDC_USERNAME_CLAIM = fromEnvOrConfig("OIDC_USERNAME_CLAIM", "cognito:username"); | |
+export const OIDC_GROUPS_CLAIM = fromEnvOrConfig("OIDC_GROUPS_CLAIM", "cognito:groups"); | |
+ | |
+ | |
+/** | |
+ * OAuth2 client id of nextstrain.org server as registered with our IdP (e.g. | |
+ * our Cognito user pool). | |
+ * | |
+ * @type {string} | |
+ */ | |
+export const OAUTH2_CLIENT_ID = fromEnvOrConfig("OAUTH2_CLIENT_ID"); | |
+ | |
+ | |
+/** | |
+ * Optional OAuth2 client secret corresponding to the {@link OAUTH2_CLIENT_ID}. | |
* | |
* @type {string} | |
*/ | |
-export const COGNITO_CLIENT_ID = fromEnvOrConfig("COGNITO_CLIENT_ID"); | |
+export const OAUTH2_CLIENT_SECRET = fromEnvOrConfig("OAUTH2_CLIENT_SECRET", null); | |
/** | |
- * OAuth2 client id of Nextstrain CLI as registered with our Cognito user pool. | |
+ * OAuth2 client id of Nextstrain CLI as registered with our IdP (e.g. Cognito | |
+ * user pool). | |
* | |
* Used to identify its tokens provided via Bearer auth. | |
* | |
* @type {string} | |
*/ | |
-export const COGNITO_CLI_CLIENT_ID = fromEnvOrConfig("COGNITO_CLI_CLIENT_ID"); | |
+export const OAUTH2_CLI_CLIENT_ID = fromEnvOrConfig("OAUTH2_CLI_CLIENT_ID"); | |
/** |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment