Skip to content

Instantly share code, notes, and snippets.

@snewell92
Last active July 23, 2023 11:35
Show Gist options
  • Save snewell92/712137e2345c6307b88ddb04d4a0a62d to your computer and use it in GitHub Desktop.
Save snewell92/712137e2345c6307b88ddb04d4a0a62d to your computer and use it in GitHub Desktop.
Sample Feathers routing with express like a traditional semi-session option
import authentication = require('feathers-authentication');
const jwt = require('feathers-authentication-jwt');
const local = require('feathers-authentication-local');
const extractJWT = jwt.ExtractJwt;
import { Application } from 'feathers';
import { Request } from 'express';
// !! This service is different than the default.
// I do not use this as the application, but rather pass it in explicitly.
// I usually just use .bind(null, app) so I can still use configure/use functions.
export default async function(app: Application) {
const config = app.get('authentication');
app.configure(authentication(config));
app.configure(local(config.local));
let cookieExtractor = (req: Request) => req.cookies[config.cookie.name];
app.configure(jwt({jwtFromRequest: cookieExtractor}));
app.service('authentication').hooks({
before: {
create: [
authentication.hooks.authenticate(config.strategies)
],
remove: [
authentication.hooks.authenticate('jwt')
]
}
});
return await true;
};
{
"authentication": {
"secret": "grandmamakesgr8cookies(irl this is a really long random stirng of alphanumerics)",
"strategies": [
"local",
"jwt"
],
"path": "/authentication",
"service": "users",
"jwt": {
"header": {
"type": "access"
},
"audience": "localhost",
"subject": "anonymous",
"issuer": "feathers",
"algorithm": "HS256",
"expiresIn": "1d",
"session": true
},
"local": {
"entity": "User",
"service": "users",
"usernameField": "\\username",
"passwordField": "password"
},
"session": true,
"cookie": {
"secret": "somelongstringofnumbersboi",
"enabled": true,
"name": "jwt-cookie",
"secure": false,
"httpOnly": true
}
}
}
{
"main": "dist/index.js",
"keywords": ["feathers"],
"directories": {
"lib": "src"
},
"engines": {
"node": ">= 8.0.0"
},
"ava": {
"files": [
"test/lib/test/*.js",
"test/lib/test/**/*.js"
],
"source": [
"test/lib/src/*",
"test/lib/src/**/*"
]
},
"scripts": {
"clean": "rimraf dist/ test/lib",
"build:client": "tsc -p public/src",
"app:compile": "tsc -p src",
"test:compile": "tsc -p test",
"test:run": "ava",
"pretest": "npm run test:compile",
"test": "ava",
"watch-tests": "run-p -c \"test:* -- -w \"",
"start": "node dist/",
"start:watch": "nodemon",
"start-turbo": "node --turbo --ignition dist/",
"dev": "run-p -c \"app:compile -- -w\" start:watch",
"minify-login-css": "cleancss -O 2 -o public/login-styles.min.css public/login-styles.css"
},
"dependencies": {
"@angular/common": "4.2.0",
"@angular/compiler": "4.2.0",
"@angular/core": "4.2.0",
"@angular/forms": "4.2.0",
"@angular/http": "4.2.0",
"@angular/platform-browser": "4.2.0",
"@angular/platform-browser-dynamic": "4.2.0",
"@types/cookie-parser": "1.3.30",
"bluebird": "3.5.0",
"body-parser": "1.17.2",
"compression": "1.6.2",
"cookie-parser": "1.4.3",
"cors": "2.8.3",
"ejs": "2.5.6",
"eslint": "3.19.0",
"express-vue": "3.14.3",
"feathers": "2.1.1",
"feathers-authentication": "1.2.6",
"feathers-authentication-hooks": "0.1.2",
"feathers-authentication-jwt": "0.3.1",
"feathers-authentication-local": "0.3.4",
"feathers-client": "2.2.0",
"feathers-configuration": "0.4.1",
"feathers-errors": "2.8.0",
"feathers-hooks": "2.0.1",
"feathers-hooks-common": "3.5.5",
"feathers-primus": "2.2.0",
"feathers-rest": "1.7.2",
"feathers-sequelize": "~2.0.1",
"helmet": "3.6.1",
"lodash": "4.17.4",
"mysql": "2.13.0",
"mysql2": "1.3.5",
"node-sass": "4.5.2",
"reflect-metadata": "0.1.10",
"request": "2.81.0",
"request-promise": "4.2.1",
"rxjs": "5.4.1",
"sass-loader": "6.0.6",
"sequelize": "4.1.0",
"sequelize-typescript": "0.3.5",
"serve-favicon": "2.4.3",
"systemjs": "0.20.14",
"uws": "8.14.0",
"vue": "2.3.3",
"vue-server-renderer": "2.3.3",
"winston": "2.3.1",
"zone.js": "0.8.10"
},
"devDependencies": {
"@angular/cli": "1.1.1",
"@types/body-parser": "1.16.3",
"@types/compression": "0.0.33",
"@types/cors": "2.8.1",
"@types/helmet": "0.0.35",
"@types/mocha": "2.2.41",
"@types/node": "7.0.29",
"@types/request-promise": "4.1.34",
"@types/sequelize": "4.0.59",
"@types/serve-favicon": "2.2.28",
"@types/winston": "2.3.3",
"ava": "0.19.1",
"clean-css-cli": "4.1.5",
"nodemon": "1.11.0",
"npm-run-all": "4.0.2",
"rimraf": "2.6.1",
"source-map-support": "0.4.15",
"ts-mockito": "2.0.0",
"typescript": "2.3.4"
}
}
const _ = require('lodash');
const auth = require('feathers-authentication');
const logger = require('winston');
import { Request, Response, RequestHandler } from 'express';
import feathers = require('feathers');
export default function (this: feathers.Application & { authenticate: any }) {
const app = this;
let authOpts = app.get('authentication');
// Declare middleware for logging a user in, setting the cookie, and redirecting
let logUserIn: RequestHandler = async (req, res, next) => {
// TODO when services become typed, type this result
let result: any = await app.authenticate('local', authOpts)(req);
if(result.fail) {
res.status(302);
return res.redirect('/?fail=true');
}
if(!result.success) {
console.error('Warning. Impossible State. User logged in succesfully but success flag marked false.');
res.status(404);
return;
}
next();
}
let setJWTToken: RequestHandler = async (req, res: Response & { data: any }, next) => {
res.data = await app.service('authentication').create({username: req.body.username, password: req.body.password});
next();
}
let redirect: RequestHandler = (req, res) => {
res.status(302);
// TODO determine proper home route based on the User's Role
return res.redirect('/admin-home');
};
// add in login POST route
app.post('/login', logUserIn, setJWTToken, auth.express.setCookie(authOpts), redirect);
// in production we'll probably use nginx, but this is useful for dev
app.use('/', feathers.static(app.get('public')));
return app;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment