diff --git a/.gitignore b/.gitignore index 8d59ab3..7720da1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .* !.gitignore flask_session/ +node_modules diff --git a/nodejs/README.md b/nodejs/README.md new file mode 100644 index 0000000..34f7d8b --- /dev/null +++ b/nodejs/README.md @@ -0,0 +1,6 @@ +## How to run +``` +npm install +node app.js +``` +App runs on port 3000 by default. diff --git a/nodejs/app.js b/nodejs/app.js new file mode 100644 index 0000000..a4f6213 --- /dev/null +++ b/nodejs/app.js @@ -0,0 +1,68 @@ +const cookieParser = require("cookie-parser") +const fetch = require("node-fetch") +const express = require("express") +const session = require("express-session") +const OAuth2Strategy = require("passport-oauth2") +const passport = require("passport") + +// Check for environment variables +const variables = ["CLIENT_ID", "CLIENT_SECRET", "SERVER_METADATA_URL"] +variables.forEach((variable) => { + if (!Object.keys(process.env).includes(variable)) { + console.log(`Missing ${variable}`) + process.exit(1) + } +}) + +// Configure application +const app = express() +const port = 3000 +app.set("view engine", "ejs") +app.use(cookieParser()); +app.use(session({ + secret: "example-secret", + resave: false, + saveUninitialized: false +})) +app.use(passport.initialize()) +app.use(passport.session()) + +// Configure OAuth +fetch(process.env["SERVER_METADATA_URL"]) + .then(res => res.json()) + .then(config => { + passport.use(new OAuth2Strategy({ + authorizationURL: config["authorization_endpoint"], + tokenURL: config["token_endpoint"], + clientID: process.env["CLIENT_ID"], + clientSecret: process.env["CLIENT_SECRET"], + callbackURL: `http://localhost:${port}/callback` + }, (accessToken, refreshToken, profile, cb) => { + fetch(`${config["userinfo_endpoint"]}?access_token=${accessToken}`) + .then(res => res.json()) + .then(json => {return cb(null, json)}) + })) + passport.serializeUser((user, done) => {done(null, user);}); + passport.deserializeUser((user, done) => {done(null, user);}) + }) + +app.get("/", (req, res) => { + res.render("index", {userinfo: req.user}) +}) + +app.get('/callback', passport.authenticate('oauth2', { + successRedirect: '/', + failureRedirect: '/login' +})) + +app.get("/login", passport.authenticate("oauth2", { + session: true, + scope: ["openid", "profile", "email"] +})) + +app.get("/logout", (req, res) => { + req.logout(); + res.redirect("/") +}) + +app.listen(port) diff --git a/nodejs/package.json b/nodejs/package.json new file mode 100644 index 0000000..bc25aba --- /dev/null +++ b/nodejs/package.json @@ -0,0 +1,21 @@ +{ + "name": "cs50-id", + "version": "1.0.0", + "description": "Sample code for using CS50 ID to authenticate users via HarvardKey, Princeton CAS, or Yale CAS.", + "main": "app.js", + "dependencies": { + "cookie-parser": "^1.4.5", + "ejs": "^3.1.6", + "express": "^4.17.1", + "express-session": "^1.17.2", + "node-fetch": "^2.6.1", + "passport": "^0.4.1", + "passport-oauth2": "^1.6.0" + }, + "devDependencies": {}, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "CS50", + "license": "ISC" +} diff --git a/nodejs/views/index.ejs b/nodejs/views/index.ejs new file mode 100644 index 0000000..479dd89 --- /dev/null +++ b/nodejs/views/index.ejs @@ -0,0 +1,31 @@ + + + +
+ + ++ You are logged in. +
+sub
<%=userinfo.sub%>
name
<%=userinfo.name%>
email
<%=userinfo.email%>
+ Log out. +
+ <%} else {%> ++ You are not logged in. Log in. +
+ <%}%> + +