-
Notifications
You must be signed in to change notification settings - Fork 0
Add NodeJS example #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
.* | ||
!.gitignore | ||
flask_session/ | ||
node_modules |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
## How to run | ||
``` | ||
npm install | ||
node app.js | ||
``` | ||
App runs on port 3000 by default. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can/should we use http://www.passportjs.org/docs/openid/ instead? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The passport-openid library requires the user to enter their OpenID identifier for authentication, not sure if this is the expected user interaction like other examples? I also don't see where it can set client_id/client_secret etc. I tried to make this NodeJS implementation similar to Django and Flask examples. In those examples, it appeared that they were using the OAuth library, which I was also using OAuth in this NodeJS example. And I forgot the exact reasons why I ended up not using passport-openid, but I did spend a fair amount of time experimenting passport-openid and decided not to use it. |
||
|
||
// Check for environment variables | ||
const variables = ["CLIENT_ID", "CLIENT_SECRET", "SERVER_METADATA_URL"] | ||
variables.forEach((variable) => { | ||
if (!Object.keys(process.env).includes(variable)) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's use 4 spaces throughout? |
||
console.log(`Missing ${variable}`) | ||
process.exit(1) | ||
} | ||
}) | ||
|
||
// Configure application | ||
const app = express() | ||
const port = 3000 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's use 8080 for IDE's sake for now? |
||
app.set("view engine", "ejs") | ||
app.use(cookieParser()); | ||
app.use(session({ | ||
secret: "example-secret", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can Express use file storage instead of signed cookies, to avoid secrets? |
||
resave: false, | ||
saveUninitialized: false | ||
})) | ||
app.use(passport.initialize()) | ||
app.use(passport.session()) | ||
|
||
// Configure OAuth | ||
fetch(process.env["SERVER_METADATA_URL"]) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I suspect we can avoid |
||
.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` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there a way to avoid hardcoding the host and port, instead letting |
||
}, (accessToken, refreshToken, profile, cb) => { | ||
fetch(`${config["userinfo_endpoint"]}?access_token=${accessToken}`) | ||
.then(res => res.json()) | ||
.then(json => {return cb(null, json)}) | ||
})) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's try using callbacks instead of promises, assuming OpenID library simplifies this too? |
||
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) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's update these versions and packages as needed, since it's been a while? |
||
}, | ||
"devDependencies": {}, | ||
"scripts": { | ||
"test": "echo \"Error: no test specified\" && exit 1" | ||
}, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's omit |
||
"author": "CS50", | ||
"license": "ISC" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
<!DOCTYPE html> | ||
|
||
<html lang="en"> | ||
<head> | ||
<meta charset="utf-8"> | ||
<meta name="viewport" content="initial-scale=1, width=device-width"> | ||
<title>nodejs</title> | ||
</head> | ||
<body> | ||
<%if (userinfo) {%> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does EJS not recommend spaces after/before |
||
<p> | ||
You are logged in. | ||
</p> | ||
<dl> | ||
<dt><code>sub</code></dt> | ||
<dt><code><%=userinfo.sub%></code></dt> | ||
<dt><code>name</code></dt> | ||
<dt><code><%=userinfo.name%></code></dt> | ||
<dt><code>email</code></dt> | ||
<dt><code><%=userinfo.email%></code></dt> | ||
</dl> | ||
<p> | ||
<a href="/logout">Log out</a>. | ||
</p> | ||
<%} else {%> | ||
<p> | ||
You are not logged in. <a href="/login">Log in</a>. | ||
</p> | ||
<%}%> | ||
</body> | ||
</html> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's use semicolons at ends of statements for consistency?