move provider factories from router to src/providers

This commit is contained in:
Raghunandan
2020-05-18 22:24:39 +02:00
parent 6757352a79
commit 422d85b67d
6 changed files with 130 additions and 165 deletions
@@ -8,13 +8,4 @@ export const providers = [
passReqToCallback: true,
},
},
// {
// provider: 'github',
// options: {
// clientID: process.env.GITHUB_CLIENT_ID!,
// clientSecret: process.env.GITHUB_CLIENT_SECRET!,
// callbackURL: 'http://localhost:7000/auth/github/handler/frame',
// passReqToCallback: true,
// },
// },
];
@@ -0,0 +1,67 @@
import passport from 'passport';
import express from 'express';
import Router from 'express-promise-router';
import { Strategy as GoogleStrategy } from 'passport-google-oauth20';
import { AuthProviderHandlers, AuthResponse } from './../types';
export const provider = {
makeStrategy(options: any): passport.Strategy {
return new GoogleStrategy(options, function (
_req: any,
accessToken: any,
refreshToken: any,
profile: any,
cb: any,
) {
cb(undefined, { profile, accessToken, refreshToken });
});
},
makeRouter(handlers: AuthProviderHandlers): express.Router {
const router = Router();
router.get('/start', handlers.start);
router.get('/handler/frame', handlers.handle);
router.get('/logout', handlers.logout);
if (handlers.refresh) {
router.get('/refreshToken', handlers.refresh);
}
return router;
},
};
export const GoogleAuthProviderHandler: AuthProviderHandlers = {
start(req, res, next) {
return passport.authenticate('google', {
scope: ['profile', 'email'],
accessType: 'offline',
prompt: 'consent',
state: '8745634875963',
})(req, res, next);
},
handle(req, res, next) {
return passport.authenticate('google', function (_, user) {
postMessageResponse(res, {
type: 'oauth-result',
payload: user,
});
})(req, res, next);
},
logout(_req, res, _next) {
return res.send('logout!');
},
};
const postMessageResponse = (res: express.Response, data: AuthResponse) => {
const jsonData = JSON.stringify(data);
const base64Data = Buffer.from(jsonData, 'utf8').toString('base64');
res.setHeader('X-Frame-Options', 'sameorigin');
res.end(`
<html>
<body>
<script>
(window.opener || window.parent).postMessage(JSON.parse(atob('${base64Data}')), location.origin)
</script>
</body>
</html>
`);
};
@@ -1,34 +0,0 @@
import express from 'express';
import Router from 'express-promise-router';
import passport from 'passport';
export const router = Router();
router.get('/start', (req, res, next) => {
passport.authenticate('google', {
scope: ['profile', 'email'],
accessType: 'offline',
prompt: 'consent',
state: '8745634875963',
})(req, res, next);
});
router.get('/handler/frame', passport.authenticate('google'), function (
req,
res,
) {
console.log('DEBUG: req.session.passport.user', req.session?.passport.user);
console.log('DEBUG: req.params =', req.params);
console.log('DEBUG: req.url =', req.url);
res.send('yay!');
});
router.get('/logout', async (_req: express.Request, res: express.Response) => {
res.send('google provider logout');
});
router.get(
'/refreshToken',
async (_req: express.Request, res: express.Response) => {
res.send('google provider refreshToken');
},
);
@@ -0,0 +1,17 @@
import { AuthProvider } from './types';
import {
provider as GoogleAuthProvider,
GoogleAuthProviderHandler,
} from './google/provider';
const providerFactories: AuthProvider = {
google: GoogleAuthProvider,
};
export const makeProvider = (config: any) => {
const provider = config.provider;
const providerFactory = providerFactories[provider];
const strategy = providerFactory.makeStrategy(config.options);
const providerRouter = providerFactory.makeRouter(GoogleAuthProviderHandler);
return { provider, strategy, providerRouter };
};
@@ -0,0 +1,44 @@
import express from 'express';
import passport from 'passport';
export type AuthProviderHandlers = {
start(
req: express.Request,
res: express.Response,
next: express.NextFunction,
): Promise<any>;
handle(
req: express.Request,
res: express.Response,
next: express.NextFunction,
): express.Response<any>;
refresh?(
req: express.Request,
res: express.Response,
next: express.NextFunction,
): Promise<any>;
logout(
req: express.Request,
res: express.Response,
next: express.NextFunction,
): express.Response<any>;
};
export type AuthProvider = {
[key: string]: {
makeStrategy(options: any): passport.Strategy;
makeRouter(handlers: AuthProviderHandlers): express.Router;
};
};
export type AuthInfo = {
profile: passport.Profile;
accessToken: string;
refreshToken?: string;
expiresAt?: number;
};
export type AuthResponse = {
type: string;
payload: AuthInfo;
};
+2 -122
View File
@@ -17,139 +17,23 @@
import express from 'express';
import Router from 'express-promise-router';
import passport from 'passport';
import { Strategy as GoogleStrategy } from 'passport-google-oauth20';
import { Logger } from 'winston';
import { providers } from './../providers/config';
import { makeProvider } from '../providers';
export interface RouterOptions {
logger: Logger;
}
type AuthProviderHandlers = {
start(
req: express.Request,
res: express.Response,
next: express.NextFunction,
): Promise<any>;
handle(
req: express.Request,
res: express.Response,
next: express.NextFunction,
): express.Response<any>;
refresh?(
req: express.Request,
res: express.Response,
next: express.NextFunction,
): Promise<any>;
logout(
req: express.Request,
res: express.Response,
next: express.NextFunction,
): express.Response<any>;
};
type AuthProvider = {
[key: string]: {
makeStrategy(options: any): passport.Strategy;
makeRouter(handlers: AuthProviderHandlers): express.Router;
};
};
type AuthInfo = {
profile: passport.Profile;
accessToken: string;
refreshToken?: string;
expiresAt?: number;
};
type AuthResponse = {
type: string;
payload: AuthInfo;
};
const postMessageResponse = (res: express.Response, data: AuthResponse) => {
const jsonData = JSON.stringify(data);
const base64Data = Buffer.from(jsonData, 'utf8').toString('base64');
res.setHeader('X-Frame-Options', 'sameorigin');
res.end(`
<html>
<body>
<script>
(window.opener || window.parent).postMessage(JSON.parse(atob('${base64Data}')), location.origin)
</script>
</body>
</html>
`);
};
const GoogleAuthProviderHandler: AuthProviderHandlers = {
start(req, res, next) {
return passport.authenticate('google', {
scope: ['profile', 'email'],
accessType: 'offline',
prompt: 'consent',
state: '8745634875963',
})(req, res, next);
},
handle(req, res, next) {
return passport.authenticate('google', function (_, user) {
postMessageResponse(res, {
type: 'oauth-result',
payload: user,
});
})(req, res, next);
},
logout(_req, res, _next) {
return res.send('logout!');
},
};
const providerFactories: AuthProvider = {
google: {
makeStrategy(options: any): passport.Strategy {
return new GoogleStrategy(options, function (
_req: any,
accessToken: any,
refreshToken: any,
profile: any,
cb: any,
) {
cb(undefined, { profile, accessToken, refreshToken });
});
},
makeRouter(handlers: AuthProviderHandlers): express.Router {
const router = Router();
router.get('/start', handlers.start);
router.get('/handler/frame', handlers.handle);
router.get('/logout', handlers.logout);
if (handlers.refresh) {
router.get('/refreshToken', handlers.refresh);
}
return router;
},
},
};
function makeProvider(config: any) {
const provider = config.provider;
const providerFactory = providerFactories[provider];
const strategy: passport.Strategy = providerFactory.makeStrategy(
config.options,
);
const providerRouter = providerFactory.makeRouter(GoogleAuthProviderHandler);
return { provider, strategy, providerRouter };
}
export async function createRouter(
options: RouterOptions,
): Promise<express.Router> {
const router = Router();
// configure all the providers
for (const providerConfig of providers) {
const { provider, strategy, providerRouter } = makeProvider(providerConfig);
passport.use(strategy);
router.use(`/${provider}`, providerRouter);
}
@@ -164,9 +48,5 @@ export async function createRouter(
router.use(passport.initialize());
router.use(passport.session());
router.get('/ping', async (_req, res) => {
res.status(200).send('pong');
});
return router;
}