diff --git a/README.md b/README.md index 3141c95..379bc95 100644 --- a/README.md +++ b/README.md @@ -31,9 +31,12 @@ Usage: hydra-token get [options] Calls Hydra's endpoints to request an access token that can be used to request data from the GraphQL API authenticated as this user. Options: - -p, --public-url A Hydra public OAuth URL that can be accessed from this computer. Must NOT end with a `/`. Default is http://localhost:4444 - -a, --admin-url A Hydra private admin URL that can be accessed from this computer. Must NOT end with a `/`. Default is http://localhost:4445 - -h, --help output usage information + -r,--raw Return the raw access token string, for piping or programmatic use + -p,--public-url A Hydra public OAuth URL that can be accessed from this computer. Default is + http://localhost:4444 + -a,--admin-url A Hydra private admin URL that can be accessed from this computer. Default is + http://localhost:4445 + -h, --help output usage information ``` ### Other Commands diff --git a/src/cli.js b/src/cli.js index 3527205..7a98d8a 100755 --- a/src/cli.js +++ b/src/cli.js @@ -17,16 +17,21 @@ program.version(packageJson.version); program .command("get ") .description("Calls Hydra's endpoints to request an access token that can be used to request data from the GraphQL API authenticated as this user.") - .option("-p,--public-url ", "A Hydra public OAuth URL that can be accessed from this computer. Must NOT end with a `/`. Default is http://localhost:4444") - .option("-a,--admin-url ", "A Hydra private admin URL that can be accessed from this computer. Must NOT end with a `/`. Default is http://localhost:4445") + .option("-r,--raw", "Return the raw access token string, for piping or programmatic use") + .option("-p,--public-url ", "A Hydra public OAuth URL that can be accessed from this computer. Default is http://localhost:4444") + .option("-a,--admin-url ", "A Hydra private admin URL that can be accessed from this computer. Default is http://localhost:4445") .action((userId, options) => { getAccessToken(userId, { hydraAdminUrl: options.adminUrl, hydraOAuthUrl: options.publicUrl }) .then((accessToken) => { - console.log(`\nAccess token for user ${userId}:\n\n${accessToken}\n`); - console.log(`Paste this in GraphQL Playground "HTTP HEADERS" box:\n{\n "Authorization": "${accessToken}"\n}\n`); + if (options.raw) { + console.log(accessToken); + } else { + console.log(`\nAccess token for user ${userId}:\n\n${accessToken}\n`); + console.log(`Paste this in GraphQL Playground "HTTP HEADERS" box:\n{\n "Authorization": "${accessToken}"\n}\n`); + } return null; }) .catch((error) => { diff --git a/src/ensureHydraClient.js b/src/ensureHydraClient.js index ec12089..c582744 100644 --- a/src/ensureHydraClient.js +++ b/src/ensureHydraClient.js @@ -1,7 +1,7 @@ /* eslint-disable no-console */ -const { URL } = require("url"); const fetch = require("node-fetch"); +const makeAbsolute = require("./makeAbsolute"); const OAUTH2_CLIENT_ID = "get-token-dev-script"; const OAUTH2_CLIENT_SECRET = "get-token-dev-script-secret"; @@ -20,11 +20,6 @@ const hydraClient = { }; /* eslint-enable camelcase */ -const makeAbsolute = (relativeUrl, baseUrl) => { - const url = new URL(relativeUrl, baseUrl); - return url.href; -}; - /** * @summary Calls Hydra's endpoint to create an OAuth client for this application * if one does not already exist. This works because the Hydra admin port diff --git a/src/getAccessToken.js b/src/getAccessToken.js index 466d38c..be3cc32 100644 --- a/src/getAccessToken.js +++ b/src/getAccessToken.js @@ -4,6 +4,7 @@ const { URL } = require("url"); const fetch = require("node-fetch"); const simpleOAuth2 = require("simple-oauth2"); const ensureHydraClient = require("./ensureHydraClient"); +const makeAbsolute = require("./makeAbsolute"); const HYDRA_OAUTH_URL = "http://localhost:4444"; const HYDRA_ADMIN_URL = "http://localhost:4445"; @@ -62,7 +63,7 @@ async function getAccessToken(userId, options) { const challenge = redirect1Parsed.searchParams.get("login_challenge"); const cookie = startLoginResult.headers.get("set-cookie"); - const acceptLoginResult = await fetch(`${hydraAdminUrl}/oauth2/auth/requests/login/accept?login_challenge=${challenge}`, { + const acceptLoginResult = await fetch(`${makeAbsolute("/oauth2/auth/requests/login/accept", hydraAdminUrl)}?login_challenge=${challenge}`, { method: "PUT", body: JSON.stringify({ subject: userId, @@ -91,7 +92,7 @@ async function getAccessToken(userId, options) { const consentChallenge = redirect3Parsed.searchParams.get("consent_challenge"); const nextCookies = continueLoginResult.headers.raw()["set-cookie"]; - const consentResult = await fetch(`${hydraAdminUrl}/oauth2/auth/requests/consent/accept?consent_challenge=${consentChallenge}`, { + const consentResult = await fetch(`${makeAbsolute("/oauth2/auth/requests/consent/accept", hydraAdminUrl)}?consent_challenge=${consentChallenge}`, { method: "PUT", body: JSON.stringify({ grant_scope: ["openid"], // eslint-disable-line camelcase diff --git a/src/makeAbsolute.js b/src/makeAbsolute.js new file mode 100644 index 0000000..52a3cfe --- /dev/null +++ b/src/makeAbsolute.js @@ -0,0 +1,15 @@ +const { URL } = require("url"); + +/** + * @summary Combine a relative URL with a base URL in a way that + * will gracefully handle extra slashes and such + * @param {String} relativeUrl Relative URL path + * @param {String} baseUrl Base URL path + * @return {String} full URL + */ +function makeAbsolute(relativeUrl, baseUrl) { + const url = new URL(relativeUrl, baseUrl); + return url.href; +} + +module.exports = makeAbsolute;