@inrupt/generate-oidc-token
Advanced tools
Comparing version 0.0.1-featinitial-bootstrap-app-427991860-24-1608205820.0 to 0.0.1-featstatic-registration-430473580-27-1608295713.0
@@ -28,53 +28,75 @@ "use strict"; | ||
const solid_client_authn_node_1 = require("@inrupt/solid-client-authn-node"); | ||
const argv = require("yargs/yargs")(process.argv.slice(2)) | ||
.describe("oidcIssuer", "The identity provider at which the user should authenticate.") | ||
.alias("issuer", "oidcIssuer") | ||
.describe("clientName", "The name of the bootstrapped app.") | ||
.demandOption(["oidcIssuer"]) | ||
.locale("en") | ||
.help().argv; | ||
const express_1 = __importDefault(require("express")); | ||
const app = express_1.default(); | ||
const PORT = 3001; | ||
const iriBase = `http://localhost:${PORT}`; | ||
const storage = new solid_client_authn_node_1.InMemoryStorage(); | ||
// Initialised when the server comes up and is running... | ||
let session; | ||
const server = app.listen(PORT, async () => { | ||
session = new solid_client_authn_node_1.Session({ | ||
const prompts_1 = require("./prompts"); | ||
async function main() { | ||
var _a, _b, _c, _d; | ||
// Get CLI arguments | ||
const argv = require("yargs/yargs")(process.argv.slice(2)) | ||
.describe("identityProvider", "The identity provider at which the user should authenticate.") | ||
.alias("idp", "identityProvider") | ||
.describe("clientName", "The name of the bootstrapped app.") | ||
.describe("registration", "[static] if you want to manually register the client, [dynamic] otherwise.") | ||
.describe("port", "The port number on which the identity provider will return the token.") | ||
.locale("en") | ||
.help().argv; | ||
const inputOptions = argv; | ||
// Complete CLI arguments with user prompt | ||
const validatedOptions = { | ||
identityProvider: (_a = inputOptions.identityProvider) !== null && _a !== void 0 ? _a : (await prompts_1.promptIdp()), | ||
registrationType: (_b = inputOptions.registrationType) !== null && _b !== void 0 ? _b : (await prompts_1.promptRegistration()), | ||
clientName: (_c = inputOptions.clientName) !== null && _c !== void 0 ? _c : (await prompts_1.promptClientName()), | ||
}; | ||
const port = (_d = argv.port) !== null && _d !== void 0 ? _d : (await prompts_1.promptPort()); | ||
const app = express_1.default(); | ||
const iriBase = `http://localhost:${port}`; | ||
const storage = new solid_client_authn_node_1.InMemoryStorage(); | ||
const session = new solid_client_authn_node_1.Session({ | ||
insecureStorage: storage, | ||
secureStorage: storage, | ||
}); | ||
console.log(`Listening at: [http://localhost:${PORT}].`); | ||
console.log(`Logging in ${argv.oidcIssuer} to get a refresh token.`); | ||
session | ||
.login({ | ||
clientName: argv.clientName, | ||
oidcIssuer: argv.oidcIssuer, | ||
redirectUrl: iriBase, | ||
tokenType: "DPoP", | ||
handleRedirect: (url) => { | ||
console.log(`\nPlease visit ${url} in a web browser.\n`); | ||
}, | ||
}) | ||
.catch((e) => { | ||
throw new Error(`Login failed: ${e.toString()}`); | ||
const server = app.listen(port, async () => { | ||
console.log(`Listening at: [${iriBase}].`); | ||
const loginOptions = { | ||
clientName: validatedOptions.clientName, | ||
oidcIssuer: validatedOptions.identityProvider, | ||
redirectUrl: iriBase, | ||
tokenType: "DPoP", | ||
handleRedirect: (url) => { | ||
console.log(`\nPlease visit ${url} in a web browser.\n`); | ||
}, | ||
}; | ||
let clientInfo; | ||
if (validatedOptions.registrationType === "static") { | ||
console.log(`Please go perform the static registration of your application to [${validatedOptions.identityProvider}].`); | ||
console.log(`The redirect IRI will be ${iriBase}`); | ||
console.log("At the end of the registration process, you should get a client ID and secret."); | ||
clientInfo = await prompts_1.promptStaticClientInfo(); | ||
loginOptions.clientId = clientInfo.clientId; | ||
loginOptions.clientSecret = clientInfo.clientSecret; | ||
} | ||
console.log(`Logging in ${validatedOptions.identityProvider} to get a refresh token.`); | ||
session.login(loginOptions).catch((e) => { | ||
throw new Error(`Login failed: ${e.toString()}`); | ||
}); | ||
}); | ||
}); | ||
app.get("/", async (_req, res) => { | ||
console.log("Login successful."); | ||
await session.handleIncomingRedirect(`${iriBase}${_req.url}`); | ||
// NB: This is a temporary approach, and we have work planned to properly | ||
// collect the token. Please note that the next line is not part of the public | ||
// API, and is therefore likely to break on non-major changes. | ||
const rawStoredSession = await storage.get(`solidClientAuthenticationUser:${session.info.sessionId}`); | ||
if (rawStoredSession === undefined) { | ||
throw new Error(`Cannot find session with ID [${session.info.sessionId}] in storage.`); | ||
} | ||
const storedSession = JSON.parse(rawStoredSession); | ||
console.log(`\nRefresh token: [${storedSession.refreshToken}]`); | ||
console.log(`Client ID: [${storedSession.clientId}]`); | ||
console.log(`Client Secret: [${storedSession.clientSecret}]`); | ||
res.send("The tokens have been sent to the bootstraping app. You can close this window."); | ||
server.close(); | ||
}); | ||
app.get("/", async (_req, res) => { | ||
console.log("Login successful."); | ||
await session.handleIncomingRedirect(`${iriBase}${_req.url}`); | ||
// NB: This is a temporary approach, and we have work planned to properly | ||
// collect the token. Please note that the next line is not part of the public | ||
// API, and is therefore likely to break on non-major changes. | ||
const rawStoredSession = await storage.get(`solidClientAuthenticationUser:${session.info.sessionId}`); | ||
if (rawStoredSession === undefined) { | ||
throw new Error(`Cannot find session with ID [${session.info.sessionId}] in storage.`); | ||
} | ||
const storedSession = JSON.parse(rawStoredSession); | ||
console.log(`\nRefresh token: [${storedSession.refreshToken}]`); | ||
console.log(`Client ID: [${storedSession.clientId}]`); | ||
console.log(`Client Secret: [${storedSession.clientSecret}]`); | ||
res.send("The tokens have been sent to the bootstraping app. You can close this window."); | ||
server.close(); | ||
}); | ||
} | ||
// Asynchronous operations are required to get user prompt, and top-level await | ||
// are not supported yet, which is why an async main is used. | ||
void main(); |
{ | ||
"name": "@inrupt/generate-oidc-token", | ||
"version": "0.0.1-featinitial-bootstrap-app-427991860-24-1608205820.0", | ||
"version": "0.0.1-featstatic-registration-430473580-27-1608295713.0", | ||
"description": "A small app to help scripts access private resources on Solid Pods", | ||
@@ -12,3 +12,3 @@ "main": "dist/index.js", | ||
"check-licenses": "license-checker --production --failOn \"AGPL-1.0-only; AGPL-1.0-or-later; AGPL-3.0-only; AGPL-3.0-or-later; Beerware; CC-BY-NC-1.0; CC-BY-NC-2.0; CC-BY-NC-2.5; CC-BY-NC-3.0; CC-BY-NC-4.0; CC-BY-NC-ND-1.0; CC-BY-NC-ND-2.0; CC-BY-NC-ND-2.5; CC-BY-NC-ND-3.0; CC-BY-NC-ND-4.0; CC-BY-NC-SA-1.0; CC-BY-NC-SA-2.0; CC-BY-NC-SA-2.5; CC-BY-NC-SA-3.0; CC-BY-NC-SA-4.0; CPAL-1.0; EUPL-1.0; EUPL-1.1; EUPL-1.1; GPL-1.0-only; GPL-1.0-or-later; GPL-2.0-only; GPL-2.0-or-later; GPL-3.0; GPL-3.0-only; GPL-3.0-or-later; SISSL; SISSL-1.2; WTFPL\"", | ||
"lint": "eslint --config .eslintrc.js --fix" | ||
"lint": "eslint --config .eslintrc.js --fix; prettier --write src/*" | ||
}, | ||
@@ -31,2 +31,3 @@ "repository": { | ||
"@types/express": "^4.17.9", | ||
"@types/inquirer": "^7.3.1", | ||
"@types/jest": "^26.0.19", | ||
@@ -56,6 +57,7 @@ "@typescript-eslint/eslint-plugin": "^4.10.0", | ||
"dependencies": { | ||
"@inrupt/solid-client-authn-node": "^1.2.4", | ||
"@inrupt/solid-client-authn-node": "^1.2.5", | ||
"express": "^4.17.1", | ||
"inquirer": "^7.3.3", | ||
"yargs": "^16.2.0" | ||
} | ||
} |
161
src/index.ts
@@ -23,26 +23,64 @@ /** | ||
// The only import we need from the Node AuthN library is the Session class. | ||
import { Session, InMemoryStorage } from "@inrupt/solid-client-authn-node"; | ||
import { | ||
Session, | ||
InMemoryStorage, | ||
ILoginInputOptions, | ||
} from "@inrupt/solid-client-authn-node"; | ||
import express from "express"; | ||
const argv = require("yargs/yargs")(process.argv.slice(2)) | ||
.describe( | ||
"oidcIssuer", | ||
"The identity provider at which the user should authenticate." | ||
) | ||
.alias("issuer", "oidcIssuer") | ||
.describe("clientName", "The name of the bootstrapped app.") | ||
.demandOption(["oidcIssuer"]) | ||
.locale("en") | ||
.help().argv; | ||
import { | ||
promptClientName, | ||
promptIdp, | ||
promptPort, | ||
promptRegistration, | ||
promptStaticClientInfo, | ||
} from "./prompts"; | ||
import express from "express"; | ||
const app = express(); | ||
const PORT = 3001; | ||
const iriBase = `http://localhost:${PORT}`; | ||
const storage = new InMemoryStorage(); | ||
type InputOptions = { | ||
identityProvider?: string; | ||
clientName?: string; | ||
registrationType?: ["static, dynamic"]; | ||
}; | ||
// Initialised when the server comes up and is running... | ||
let session: Session; | ||
type ValidatedOptions = { | ||
identityProvider: string; | ||
registrationType: "static" | "dynamic"; | ||
clientName?: string; | ||
}; | ||
const server = app.listen(PORT, async () => { | ||
session = new Session({ | ||
async function main(): Promise<void> { | ||
// Get CLI arguments | ||
const argv = require("yargs/yargs")(process.argv.slice(2)) | ||
.describe( | ||
"identityProvider", | ||
"The identity provider at which the user should authenticate." | ||
) | ||
.alias("idp", "identityProvider") | ||
.describe("clientName", "The name of the bootstrapped app.") | ||
.describe( | ||
"registration", | ||
"[static] if you want to manually register the client, [dynamic] otherwise." | ||
) | ||
.describe( | ||
"port", | ||
"The port number on which the identity provider will return the token." | ||
) | ||
.locale("en") | ||
.help().argv; | ||
const inputOptions: InputOptions = argv; | ||
// Complete CLI arguments with user prompt | ||
const validatedOptions: ValidatedOptions = { | ||
identityProvider: inputOptions.identityProvider ?? (await promptIdp()), | ||
registrationType: | ||
inputOptions.registrationType ?? (await promptRegistration()), | ||
clientName: inputOptions.clientName ?? (await promptClientName()), | ||
}; | ||
const port = argv.port ?? (await promptPort()); | ||
const app = express(); | ||
const iriBase = `http://localhost:${port}`; | ||
const storage = new InMemoryStorage(); | ||
const session: Session = new Session({ | ||
insecureStorage: storage, | ||
@@ -52,8 +90,7 @@ secureStorage: storage, | ||
console.log(`Listening at: [http://localhost:${PORT}].`); | ||
console.log(`Logging in ${argv.oidcIssuer} to get a refresh token.`); | ||
session | ||
.login({ | ||
clientName: argv.clientName, | ||
oidcIssuer: argv.oidcIssuer, | ||
const server = app.listen(port, async () => { | ||
console.log(`Listening at: [${iriBase}].`); | ||
const loginOptions: ILoginInputOptions = { | ||
clientName: validatedOptions.clientName, | ||
oidcIssuer: validatedOptions.identityProvider, | ||
redirectUrl: iriBase, | ||
@@ -64,31 +101,53 @@ tokenType: "DPoP", | ||
}, | ||
}) | ||
.catch((e) => { | ||
}; | ||
let clientInfo; | ||
if (validatedOptions.registrationType === "static") { | ||
console.log( | ||
`Please go perform the static registration of your application to [${validatedOptions.identityProvider}].` | ||
); | ||
console.log(`The redirect IRI will be ${iriBase}`); | ||
console.log( | ||
"At the end of the registration process, you should get a client ID and secret." | ||
); | ||
clientInfo = await promptStaticClientInfo(); | ||
loginOptions.clientId = clientInfo.clientId; | ||
loginOptions.clientSecret = clientInfo.clientSecret; | ||
} | ||
console.log( | ||
`Logging in ${validatedOptions.identityProvider} to get a refresh token.` | ||
); | ||
session.login(loginOptions).catch((e) => { | ||
throw new Error(`Login failed: ${e.toString()}`); | ||
}); | ||
}); | ||
}); | ||
app.get("/", async (_req, res) => { | ||
console.log("Login successful."); | ||
await session.handleIncomingRedirect(`${iriBase}${_req.url}`); | ||
// NB: This is a temporary approach, and we have work planned to properly | ||
// collect the token. Please note that the next line is not part of the public | ||
// API, and is therefore likely to break on non-major changes. | ||
const rawStoredSession = await storage.get( | ||
`solidClientAuthenticationUser:${session.info.sessionId}` | ||
); | ||
if (rawStoredSession === undefined) { | ||
throw new Error( | ||
`Cannot find session with ID [${session.info.sessionId}] in storage.` | ||
app.get("/", async (_req, res) => { | ||
console.log("Login successful."); | ||
await session.handleIncomingRedirect(`${iriBase}${_req.url}`); | ||
// NB: This is a temporary approach, and we have work planned to properly | ||
// collect the token. Please note that the next line is not part of the public | ||
// API, and is therefore likely to break on non-major changes. | ||
const rawStoredSession = await storage.get( | ||
`solidClientAuthenticationUser:${session.info.sessionId}` | ||
); | ||
} | ||
const storedSession = JSON.parse(rawStoredSession); | ||
console.log(`\nRefresh token: [${storedSession.refreshToken}]`); | ||
console.log(`Client ID: [${storedSession.clientId}]`); | ||
console.log(`Client Secret: [${storedSession.clientSecret}]`); | ||
if (rawStoredSession === undefined) { | ||
throw new Error( | ||
`Cannot find session with ID [${session.info.sessionId}] in storage.` | ||
); | ||
} | ||
const storedSession = JSON.parse(rawStoredSession); | ||
console.log(`\nRefresh token: [${storedSession.refreshToken}]`); | ||
console.log(`Client ID: [${storedSession.clientId}]`); | ||
console.log(`Client Secret: [${storedSession.clientSecret}]`); | ||
res.send( | ||
"The tokens have been sent to the bootstraping app. You can close this window." | ||
); | ||
server.close(); | ||
}); | ||
res.send( | ||
"The tokens have been sent to the bootstraping app. You can close this window." | ||
); | ||
server.close(); | ||
}); | ||
} | ||
// Asynchronous operations are required to get user prompt, and top-level await | ||
// are not supported yet, which is why an async main is used. | ||
void main(); |
52931
25
637
4
15
+ Addedinquirer@^7.3.3
+ Addedansi-escapes@4.3.2(transitive)
+ Addedchalk@4.1.2(transitive)
+ Addedchardet@0.7.0(transitive)
+ Addedcli-cursor@3.1.0(transitive)
+ Addedcli-width@3.0.0(transitive)
+ Addedescape-string-regexp@1.0.5(transitive)
+ Addedexternal-editor@3.1.0(transitive)
+ Addedfigures@3.2.0(transitive)
+ Addedhas-flag@4.0.0(transitive)
+ Addedinquirer@7.3.3(transitive)
+ Addedlodash@4.17.21(transitive)
+ Addedmimic-fn@2.1.0(transitive)
+ Addedmute-stream@0.0.8(transitive)
+ Addedobject-inspect@1.13.3(transitive)
+ Addedonetime@5.1.2(transitive)
+ Addedos-tmpdir@1.0.2(transitive)
+ Addedrestore-cursor@3.1.0(transitive)
+ Addedrun-async@2.4.1(transitive)
+ Addedrxjs@6.6.7(transitive)
+ Addedsignal-exit@3.0.7(transitive)
+ Addedsupports-color@7.2.0(transitive)
+ Addedthrough@2.3.8(transitive)
+ Addedtmp@0.0.33(transitive)
+ Addedtslib@1.14.1(transitive)
+ Addedtype-fest@0.21.3(transitive)
- Removedobject-inspect@1.13.4(transitive)