Skip to content
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
a8a8fa1
feat(auth): enhance postMessage handling and improve cookie settings
yuvvantalreja May 15, 2025
6b11ad2
fix(auth): Auth Issue fixed
yuvvantalreja May 15, 2025
c37d0e7
fix(auth): Gist methods updated for new auth integration
yuvvantalreja May 15, 2025
127ac2c
fix(auth): Unified auth with local storage
yuvvantalreja May 17, 2025
4e98fb0
feat(auth): Enhance authentication flow with GitHub access token support
yuvvantalreja May 17, 2025
4271b68
refactor(auth): Implement in-time GitHub token retrieval for API calls
yuvvantalreja Jun 7, 2025
3dab1ab
Update config/passport.ts
domoritz Jun 8, 2025
293b027
remove redis
domoritz Jun 8, 2025
8fdebf3
cleanups
domoritz Jun 8, 2025
1abaffe
More cleanups
domoritz Jun 8, 2025
26e6933
Update src/controllers/auth.ts
domoritz Jun 8, 2025
364e112
Fixed lint issues
yuvvantalreja Jun 8, 2025
ff84c67
Removed console logs
yuvvantalreja Jun 8, 2025
9f977f9
Changed to use handle options
yuvvantalreja Jun 8, 2025
6c684ec
simplify, fox import
domoritz Jun 8, 2025
2cdb6dd
code style
domoritz Jun 8, 2025
b16e339
update typedoc
domoritz Jun 8, 2025
0b04191
update eslint
domoritz Jun 8, 2025
e93f322
chore: switch to npm
domoritz Jun 8, 2025
c34b907
update vscode setting
domoritz Jun 8, 2025
783aff0
update express, simplify cors
domoritz Jun 8, 2025
09a751b
debug at main url
domoritz Jun 8, 2025
1c1533d
Send token through URL
yuvvantalreja Jun 9, 2025
b6e3e76
redirect to backend
yuvvantalreja Jun 10, 2025
20aec71
Minor changes
yuvvantalreja Jun 10, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions .env.sample
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,3 @@ GITHUB_CLIENT_SECRET=# client secret of the application

# Session ID configuration
SESSION_SECRET=# secret key for session ID generation

# Redis session store configuration
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD=
2 changes: 1 addition & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"curly": ["error", "all"],
"eol-last": ["error", "always"],
"keyword-spacing": ["error", { "before": true, "after": true }],
"max-len": ["error", { "code": 80 }],
"max-len": ["error", { "code": 120 }],
"no-console": ["error", { "allow": ["warn", "error"] }],
"no-dupe-class-members": "error",
"no-mixed-operators": "error",
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ https://github.com/vega/editor-backend.

# GitHub OAuth app credentials
GITHUB_CLIENT_ID=a901f0948b144d29fbdf
GITHUB_CLIENT_SECRET=dfdb84ff29fde4eaa160078d13e024530238ebe0
GITHUB_CLIENT_SECRET=8a2269fd225321f19f2a19e7629e3ad63d94df68
Comment thread
domoritz marked this conversation as resolved.

# Session ID configuration
SESSION_SECRET=secret
Expand Down
20 changes: 1 addition & 19 deletions config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,24 +22,6 @@ export const githubOauth = {
GITHUB_CLIENT_SECRET: process.env.GITHUB_CLIENT_SECRET,
};

/**
* Stores the configuration for redis store.
*/
export const redisConfiguration = {
/**
* Host name for redis store.
*/
REDIS_HOST: process.env.REDIS_HOST,
/**
* Host password for redis store.
*/
REDIS_PASSWORD: process.env.REDIS_PASSWORD,
/**
* Port number for redis store.
*/
REDIS_PORT: +process.env.REDIS_PORT,
};

/**
* Secret used to sign the session ID cookie.
*
Expand Down Expand Up @@ -67,7 +49,7 @@ export const allowedOrigins: string[] = [
* Stores the type of environment of project. It is either `development` or
* `production`.
*
* _Exported as `nodeEnv` to differentiate behaviour of app on development and
* _Exported as `nodeEnv` to differentiate behavior of app on development and
* production server._
*/
export const nodeEnv: string = process.env.NODE_ENV;
Expand Down
36 changes: 12 additions & 24 deletions config/passport.ts
Original file line number Diff line number Diff line change
@@ -1,37 +1,15 @@
import passport from 'passport';
import passportGitHub from 'passport-github2';

import { githubOauth } from './index';
import { authUrl, hostUrl } from '../src/urls';
import { githubOauth } from './index.js';
import { authUrl, hostUrl } from '../src/urls.js';

/**
* OAuth strategy to authenticate with GitHub. Reference:
* http://www.passportjs.org/packages/passport-github2/
*/
const GitHubStrategy = passportGitHub.Strategy;

/**
* Serializes user profile returned after authentication.
*
* @param {object} user User profile
* @param {function} done Method called internally by passport.js to resume
* process
*/
passport.serializeUser((user, done) => {
done(null, user);
});

/**
* Deserializes cookie sent to know which user is logged in.
*
* @param {object} user The GitHub profile of the user
* @param {function} done Method called internally by passport.js to resume
* process
*/
passport.deserializeUser((user, done) => {
done(null, user);
});

/**
* GitHub OAuth strategy configuration.
*
Expand All @@ -42,7 +20,17 @@ passport.use(new GitHubStrategy({
clientID: githubOauth.GITHUB_CLIENT_ID,
clientSecret: githubOauth.GITHUB_CLIENT_SECRET,
callbackURL: `${hostUrl}${authUrl.callback}`,
scope: ['gist'],
}, (accessToken, refreshToken, profile, done) => {

if (!profile) {
return done(new Error('Failed to retrieve GitHub profile'));
}

if (!accessToken) {
return done(new Error('No access token provided'));
}

done(null, { ...profile, accessToken });
}));

Expand Down
8 changes: 2 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"test": "echo \"Error: no test specified\" && exit 1",
"docs": "typedoc"
},
"type": "module",
"license": "BSD-3-Clause",
"repository": {
"type": "git",
Expand All @@ -35,20 +36,15 @@
},
"dependencies": {
"@octokit/graphql": "5.0.5",
"@types/connect-redis": "0.0.19",
"@types/cors": "^2.8.17",
"@types/passport": "1.0.12",
"body-parser": "^1.20.2",
"connect-redis": "^6.1.3",
"cors": "^2.8.5",
"dotenv": "^16.0.3",
"express": "^4.19.2",
"express-session": "^1.17.3",
"isomorphic-fetch": "^3.0.0",
"passport": "^0.6.0",
"passport-github2": "^0.1.12",
"pug": "^3.0.2",
"redis": "^3.1.2"
"pug": "^3.0.2"
},
"husky": {
"hooks": {
Expand Down
85 changes: 32 additions & 53 deletions src/app.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
import bodyParser from 'body-parser';
import connectRedis, { RedisStore } from 'connect-redis';
import cors from 'cors';
import express from 'express';
import session from 'express-session';
import passport from 'passport';
import redis from 'redis';
import {
cookieExpiry,
redisConfiguration,
sessionSecret,
allowedOrigins,
} from '../config/index';
import AuthController from './controllers/auth';
import Controller from './controllers/base';
import GistController from './controllers/gist';
import HomeController from './controllers/home';
} from '../config/index.js';
import AuthController from './controllers/auth.js';
import Controller from './controllers/base.js';
import HomeController from './controllers/home.js';

import { dirname } from 'node:path';
import { fileURLToPath } from 'node:url';

const __dirname = dirname(fileURLToPath(import.meta.url));

/**
* Configuration of the express application.
Expand All @@ -24,67 +22,28 @@ class App {
* Stores the constructor of Express application.
*/
public app: express.Application;
public redisClient: redis.RedisClient;
public redisStore: RedisStore;

/**
* Constructor to initialize application.
*/
constructor() {
this.app = express();
this.redisClient = redis.createClient(
redisConfiguration.REDIS_PORT,
redisConfiguration.REDIS_HOST
);
if (redisConfiguration.REDIS_PASSWORD) {
this.redisClient.auth(redisConfiguration.REDIS_PASSWORD, error => {
console.error(error);
});
}
this.redisStore = connectRedis(session);
this.initializeMiddleWares();
this.initializeControllers([
new AuthController(),
new HomeController(),
new GistController(),
]);
}

/**
* Initializes middleware for accessing request and response objects.
*/
private initializeMiddleWares() {
// Configuration for creating session cookies.
const redisStore = this.redisStore;
this.app.use(
session({
name: 'vega_session',
secret: sessionSecret,
resave: false,
saveUninitialized: false,
store: new redisStore({
host: redisConfiguration.REDIS_HOST,
port: redisConfiguration.REDIS_PORT,
client: this.redisClient,
ttl: cookieExpiry,
}),
/**
* `cookieExpiry` is converted to milliseconds. Reference:
* https://www.npmjs.com/package/express-session#cookiemaxage
*/
cookie: {
maxAge: cookieExpiry * 1000,
secure: process.env.NODE_ENV === 'production',
sameSite: 'none',
},
rolling: true,
})
);
this.app.use(bodyParser.json());

const corsOptions = {
origin: (origin, callback) => {
if (!origin || allowedOrigins.includes(origin)) {
if (!origin || origin === 'null' || allowedOrigins.includes(origin)) {
callback(null, true);
} else {
callback(new Error('Not allowed by CORS'));
Expand All @@ -94,12 +53,32 @@ class App {
};
this.app.use(cors(corsOptions));
this.app.use(passport.initialize());
this.app.use(passport.session());

// Handle preflight OPTIONS requests explicitly (required for CORS)
this.app.options('*', (req, res) => {
const origin = req.headers.origin || '*';

if (origin === 'null') {
res.header('Access-Control-Allow-Origin', 'null');
} else {
res.header('Access-Control-Allow-Origin', origin);
}

// Needed to handle CORS preflight requests.
// i.e. tell browsers which origins, methods, are allowed.

res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
// Without this, browsers may block cross-origin requests, especially when credentials are involved.
res.header('Access-Control-Allow-Headers',
'Content-Type, Authorization, X-Auth-Token, Cache-Control, Pragma, Expires');
res.header('Access-Control-Allow-Credentials', 'true');
res.header('Access-Control-Expose-Headers', 'Content-Type, Authorization, X-Auth-Token');
res.status(200).end();
});

// Put IP of https://vega.github.io/editor instead of 1
this.app.set('trust proxy', 1);

this.app.engine('pug', require('pug').__express);
this.app.set('views', `${__dirname}/views`);
this.app.set('view engine', 'pug');
}
Expand Down
Loading