@feathersjs/authentication-oauth 5.0.0-pre.27 → 5.0.0-pre.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/index.ts CHANGED
@@ -1,83 +1,46 @@
1
- import defaultsDeep from 'lodash/defaultsDeep'
2
- import each from 'lodash/each'
3
- import omit from 'lodash/omit'
4
- import { createDebug } from '@feathersjs/commons'
5
1
  import { Application } from '@feathersjs/feathers'
2
+ import { createDebug } from '@feathersjs/commons'
3
+ import { resolveDispatch } from '@feathersjs/schema'
4
+
6
5
  import { OAuthStrategy, OAuthProfile } from './strategy'
7
- import { default as setupExpress } from './express'
8
- import { OauthSetupSettings, getDefaultSettings } from './utils'
6
+ import { redirectHook, OAuthService } from './service'
7
+ import { getServiceOptions, OauthSetupSettings } from './utils'
9
8
 
10
9
  const debug = createDebug('@feathersjs/authentication-oauth')
11
10
 
12
11
  export { OauthSetupSettings, OAuthStrategy, OAuthProfile }
13
12
 
14
- export const setup = (options: OauthSetupSettings) => (app: Application) => {
15
- const service = app.defaultAuthentication ? app.defaultAuthentication(options.authService) : null
16
-
17
- if (!service) {
18
- throw new Error(
19
- 'An authentication service must exist before registering @feathersjs/authentication-oauth'
20
- )
21
- }
22
-
23
- const { oauth } = service.configuration
24
-
25
- if (!oauth) {
26
- debug('No oauth configuration found in authentication configuration. Skipping oAuth setup.')
27
- return
28
- }
29
-
30
- const { strategyNames } = service
31
-
32
- // Set up all the defaults
33
- const port = app.get('port')
34
- let host = app.get('host')
35
- let protocol = 'https'
13
+ export const oauth =
14
+ (settings: Partial<OauthSetupSettings> = {}) =>
15
+ (app: Application) => {
16
+ const authService = app.defaultAuthentication ? app.defaultAuthentication(settings.authService) : null
36
17
 
37
- // Development environments commonly run on HTTP with an extended port
38
- if (app.get('env') === 'development') {
39
- protocol = 'http'
40
- if (String(port) !== '80') {
41
- host += `:${port}`
18
+ if (!authService) {
19
+ throw new Error(
20
+ 'An authentication service must exist before registering @feathersjs/authentication-oauth'
21
+ )
42
22
  }
43
- }
44
23
 
45
- const grant = defaultsDeep({}, omit(oauth, ['redirect', 'origins']), {
46
- defaults: {
47
- prefix: '/oauth',
48
- origin: `${protocol}://${host}`,
49
- transport: 'session',
50
- response: ['tokens', 'raw', 'profile']
24
+ if (!authService.configuration.oauth) {
25
+ debug('No oauth configuration found in authentication configuration. Skipping oAuth setup.')
26
+ return
51
27
  }
52
- })
53
-
54
- const getUrl = (url: string) => {
55
- const { defaults } = grant
56
- return `${defaults.origin}${defaults.prefix}/${url}`
57
- }
58
-
59
- each(grant, (value, name) => {
60
- if (name !== 'defaults') {
61
- value.callback = value.callback || getUrl(`${name}/authenticate`)
62
- value.redirect_uri = value.redirect_uri || getUrl(`${name}/callback`)
63
28
 
64
- if (!strategyNames.includes(name)) {
65
- debug(`Registering oAuth default strategy for '${name}'`)
66
- service.register(name, new OAuthStrategy())
67
- }
29
+ const oauthOptions = {
30
+ linkStrategy: 'jwt',
31
+ ...settings
68
32
  }
69
- })
33
+ const serviceOptions = getServiceOptions(authService, oauthOptions)
70
34
 
71
- app.set('grant', grant)
72
- }
35
+ app.use('oauth/:provider', new OAuthService(authService, oauthOptions), serviceOptions)
73
36
 
74
- export const express =
75
- (settings: Partial<OauthSetupSettings> = {}) =>
76
- (app: Application) => {
77
- const options = getDefaultSettings(app, settings)
37
+ const oauthService = app.service('oauth/:provider')
78
38
 
79
- app.configure(setup(options))
80
- app.configure(setupExpress(options))
81
- }
39
+ oauthService.hooks({
40
+ around: { all: [resolveDispatch(), redirectHook()] }
41
+ })
82
42
 
83
- export const expressOauth = express
43
+ if (typeof oauthService.publish === 'function') {
44
+ app.service('oauth/:provider').publish(() => null)
45
+ }
46
+ }
package/src/service.ts ADDED
@@ -0,0 +1,177 @@
1
+ import { createDebug } from '@feathersjs/commons'
2
+ import { HookContext, NextFunction, Params } from '@feathersjs/feathers'
3
+ import { FeathersError } from '@feathersjs/errors'
4
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
5
+ //@ts-ignore
6
+ import Grant from 'grant/lib/grant'
7
+ import { AuthenticationService } from '@feathersjs/authentication'
8
+ import { OAuthStrategy } from './strategy'
9
+ import { getGrantConfig, OauthSetupSettings } from './utils'
10
+
11
+ const debug = createDebug('@feathersjs/authentication-oauth/services')
12
+
13
+ export type GrantResponse = {
14
+ location: string
15
+ session: any
16
+ state: any
17
+ }
18
+
19
+ export type OAuthParams = Omit<Params, 'route'> & {
20
+ session: any
21
+ state: Record<string, any>
22
+ route: {
23
+ provider: string
24
+ }
25
+ }
26
+
27
+ export class OAuthError extends FeathersError {
28
+ constructor(message: string, data: any, public location: string) {
29
+ super(message, 'NotAuthenticated', 401, 'not-authenticated', data)
30
+ }
31
+ }
32
+
33
+ export const redirectHook = () => async (context: HookContext, next: NextFunction) => {
34
+ try {
35
+ await next()
36
+
37
+ const { location } = context.result
38
+
39
+ debug(`oAuth redirect to ${location}`)
40
+
41
+ if (location) {
42
+ context.http = {
43
+ ...context.http,
44
+ location
45
+ }
46
+ }
47
+ } catch (error: any) {
48
+ if (error.location) {
49
+ context.http = {
50
+ ...context.http,
51
+ location: error.location
52
+ }
53
+ context.result = typeof error.toJSON === 'function' ? error.toJSON() : error
54
+ } else {
55
+ throw error
56
+ }
57
+ }
58
+ }
59
+
60
+ export class OAuthService {
61
+ grant: any
62
+
63
+ constructor(public service: AuthenticationService, public settings: OauthSetupSettings) {
64
+ const config = getGrantConfig(service)
65
+
66
+ this.grant = Grant({ config })
67
+ }
68
+
69
+ async handler(method: string, params: OAuthParams, body?: any, override?: string): Promise<GrantResponse> {
70
+ const {
71
+ session,
72
+ state,
73
+ query,
74
+ route: { provider }
75
+ } = params
76
+
77
+ const result: GrantResponse = await this.grant({
78
+ params: { provider, override },
79
+ state: state.grant,
80
+ session: session.grant,
81
+ query,
82
+ method,
83
+ body
84
+ })
85
+
86
+ session.grant = result.session
87
+ state.grant = result.state
88
+
89
+ return result
90
+ }
91
+
92
+ async authenticate(params: OAuthParams, result: GrantResponse) {
93
+ const name = params.route.provider
94
+ const { linkStrategy, authService } = this.settings
95
+ const { accessToken, grant, query = {}, redirect } = params.session
96
+ const strategy = this.service.getStrategy(name) as OAuthStrategy
97
+ const authParams = {
98
+ ...params,
99
+ authStrategies: [name],
100
+ authentication: accessToken
101
+ ? {
102
+ strategy: linkStrategy,
103
+ accessToken
104
+ }
105
+ : null,
106
+ query,
107
+ redirect
108
+ }
109
+ const payload = grant?.response || result?.session?.response || result?.state?.response || params.query
110
+ const authentication = {
111
+ strategy: name,
112
+ ...payload
113
+ }
114
+
115
+ try {
116
+ debug(`Calling ${authService}.create authentication with strategy ${name}`)
117
+
118
+ const authResult = await this.service.create(authentication, authParams)
119
+
120
+ debug('Successful oAuth authentication, sending response')
121
+
122
+ const location = await strategy.getRedirect(authResult, authParams)
123
+
124
+ if (typeof params.session.destroy === 'function') {
125
+ await params.session.destroy()
126
+ }
127
+
128
+ return {
129
+ ...authResult,
130
+ location
131
+ }
132
+ } catch (error: any) {
133
+ const location = await strategy.getRedirect(error, authParams)
134
+ const e = new OAuthError(error.message, error.data, location)
135
+
136
+ if (typeof params.session.destroy === 'function') {
137
+ await params.session.destroy()
138
+ }
139
+
140
+ e.stack = error.stack
141
+ throw e
142
+ }
143
+ }
144
+
145
+ async find(params: OAuthParams) {
146
+ const { session, query } = params
147
+ const { feathers_token, redirect, ...restQuery } = query
148
+ const handlerParams = {
149
+ ...params,
150
+ query: restQuery
151
+ }
152
+
153
+ if (feathers_token) {
154
+ debug('Got feathers_token query parameter to link accounts', feathers_token)
155
+ session.accessToken = feathers_token
156
+ }
157
+
158
+ session.redirect = redirect
159
+ session.query = restQuery
160
+
161
+ return this.handler('GET', handlerParams, {})
162
+ }
163
+
164
+ async get(override: string, params: OAuthParams) {
165
+ const result = await this.handler('GET', params, {}, override)
166
+
167
+ if (override === 'callback') {
168
+ return this.authenticate(params, result)
169
+ }
170
+
171
+ return result
172
+ }
173
+
174
+ async create(data: any, params: OAuthParams) {
175
+ return this.handler('POST', params, data)
176
+ }
177
+ }
package/src/strategy.ts CHANGED
@@ -1,7 +1,3 @@
1
- /* eslint-disable @typescript-eslint/no-unused-vars */
2
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
3
- // @ts-ignore
4
- import querystring from 'querystring'
5
1
  import {
6
2
  AuthenticationRequest,
7
3
  AuthenticationBaseStrategy,
@@ -11,6 +7,7 @@ import {
11
7
  import { Params } from '@feathersjs/feathers'
12
8
  import { NotAuthenticated } from '@feathersjs/errors'
13
9
  import { createDebug, _ } from '@feathersjs/commons'
10
+ import qs from 'qs'
14
11
 
15
12
  const debug = createDebug('@feathersjs/authentication-oauth/strategy')
16
13
 
@@ -22,7 +19,7 @@ export interface OAuthProfile {
22
19
  export class OAuthStrategy extends AuthenticationBaseStrategy {
23
20
  get configuration() {
24
21
  const { entity, service, entityId, oauth } = this.authentication.configuration
25
- const config = oauth[this.name]
22
+ const config = oauth[this.name] as any
26
23
 
27
24
  return {
28
25
  entity,
@@ -71,14 +68,14 @@ export class OAuthStrategy extends AuthenticationBaseStrategy {
71
68
  }
72
69
 
73
70
  async getAllowedOrigin(params?: Params) {
74
- const { redirect, origins } = this.authentication.configuration.oauth
71
+ const { redirect, origins = this.app.get('origins') } = this.authentication.configuration.oauth
75
72
 
76
73
  if (Array.isArray(origins)) {
77
- const referer = params?.headers?.referer || ''
74
+ const referer = params?.headers?.referer || origins[0]
78
75
  const allowedOrigin = origins.find((current) => referer.toLowerCase().startsWith(current.toLowerCase()))
79
76
 
80
77
  if (!allowedOrigin) {
81
- throw new NotAuthenticated(`Referer "${referer || '[header not available]'}" not allowed.`)
78
+ throw new NotAuthenticated(`Referer "${referer}" is not allowed.`)
82
79
  }
83
80
 
84
81
  return allowedOrigin
@@ -102,14 +99,10 @@ export class OAuthStrategy extends AuthenticationBaseStrategy {
102
99
  const separator = redirect.endsWith('?') ? '' : redirect.indexOf('#') !== -1 ? '?' : '#'
103
100
  const authResult: AuthenticationResult = data
104
101
  const query = authResult.accessToken
105
- ? {
106
- access_token: authResult.accessToken
107
- }
108
- : {
109
- error: data.message || 'OAuth Authentication not successful'
110
- }
111
-
112
- return `${redirectUrl}${separator}${querystring.stringify(query)}`
102
+ ? { access_token: authResult.accessToken }
103
+ : { error: data.message || 'OAuth Authentication not successful' }
104
+
105
+ return `${redirectUrl}${separator}${qs.stringify(query)}`
113
106
  }
114
107
 
115
108
  async findEntity(profile: OAuthProfile, params: Params) {
package/src/utils.ts CHANGED
@@ -1,17 +1,123 @@
1
- import { RequestHandler } from 'express'
2
- import { Application } from '@feathersjs/feathers'
1
+ import type { RequestHandler } from 'express'
2
+ import type { Middleware, Application as KoaApplication } from '@feathersjs/koa'
3
+
4
+ import type { ServiceOptions } from '@feathersjs/feathers'
5
+
6
+ import '@feathersjs/koa'
7
+ import '@feathersjs/express'
8
+ import expressCookieSession from 'cookie-session'
9
+ import koaCookieSession from 'koa-session'
10
+
11
+ import { AuthenticationService } from '@feathersjs/authentication'
12
+ import { GrantConfig } from 'grant'
13
+
14
+ import { defaultsDeep, each, omit } from 'lodash'
3
15
 
4
16
  export interface OauthSetupSettings {
17
+ linkStrategy: string
5
18
  authService?: string
6
19
  expressSession?: RequestHandler
7
- linkStrategy: string
20
+ koaSession?: Middleware
21
+ }
22
+
23
+ export const getGrantConfig = (service: AuthenticationService): GrantConfig => {
24
+ const {
25
+ app,
26
+ configuration: { oauth }
27
+ } = service
28
+ // Set up all the defaults
29
+ const port = app.get('port')
30
+ let host = app.get('host')
31
+ let protocol = 'https'
32
+
33
+ // Development environments commonly run on HTTP with an extended port
34
+ if (process.env.NODE_ENV !== 'production') {
35
+ protocol = 'http'
36
+ if (String(port) !== '80') {
37
+ host += `:${port}`
38
+ }
39
+ }
40
+
41
+ const grant: GrantConfig = defaultsDeep({}, omit(oauth, ['redirect', 'origins']), {
42
+ defaults: {
43
+ prefix: '/oauth',
44
+ origin: `${protocol}://${host}`,
45
+ transport: 'state',
46
+ response: ['tokens', 'raw', 'profile']
47
+ }
48
+ })
49
+
50
+ const getUrl = (url: string) => {
51
+ const { defaults } = grant
52
+ return `${defaults.origin}${defaults.prefix}/${url}`
53
+ }
54
+
55
+ each(grant, (value, name) => {
56
+ if (name !== 'defaults') {
57
+ value.redirect_uri = value.redirect_uri || getUrl(`${name}/callback`)
58
+ }
59
+ })
60
+
61
+ return grant
8
62
  }
9
63
 
10
- export const getDefaultSettings = (_app: Application, other?: Partial<OauthSetupSettings>) => {
11
- const defaults: OauthSetupSettings = {
12
- linkStrategy: 'jwt',
13
- ...other
64
+ export const setExpressParams: RequestHandler = (req, res, next) => {
65
+ req.session.destroy ||= () => {
66
+ req.session = null
14
67
  }
15
68
 
16
- return defaults
69
+ req.feathers = {
70
+ ...req.feathers,
71
+ session: req.session,
72
+ state: res.locals
73
+ }
74
+
75
+ next()
76
+ }
77
+
78
+ export const setKoaParams: Middleware = async (ctx, next) => {
79
+ ctx.session.destroy ||= () => {
80
+ ctx.session = null
81
+ }
82
+
83
+ ctx.feathers = {
84
+ ...ctx.feathers,
85
+ session: ctx.session,
86
+ state: ctx.state
87
+ } as any
88
+
89
+ await next()
90
+ }
91
+
92
+ export const getServiceOptions = (
93
+ service: AuthenticationService,
94
+ settings: OauthSetupSettings
95
+ ): ServiceOptions => {
96
+ const { secret } = service.configuration
97
+ const koaApp = service.app as KoaApplication
98
+
99
+ if (koaApp.context) {
100
+ koaApp.keys = [secret]
101
+
102
+ const { koaSession = koaCookieSession({ key: 'feathers.oauth' }, koaApp as any) } = settings
103
+
104
+ return {
105
+ koa: {
106
+ before: [koaSession, setKoaParams]
107
+ }
108
+ }
109
+ }
110
+
111
+ const {
112
+ expressSession = expressCookieSession({
113
+ name: 'feathers.oauth',
114
+ keys: [secret]
115
+ })
116
+ } = settings
117
+
118
+ return {
119
+ express: {
120
+ before: [expressSession, setExpressParams]
121
+ }
122
+ }
17
123
  }
package/lib/express.d.ts DELETED
@@ -1,19 +0,0 @@
1
- import { Application } from '@feathersjs/feathers';
2
- import { OauthSetupSettings } from './utils';
3
- declare module 'express-session' {
4
- interface SessionData {
5
- redirect: string;
6
- accessToken: string;
7
- query: {
8
- [key: string]: any;
9
- };
10
- grant: {
11
- [key: string]: any;
12
- };
13
- headers: {
14
- [key: string]: any;
15
- };
16
- }
17
- }
18
- declare const _default: (options: OauthSetupSettings) => (feathersApp: Application) => void;
19
- export default _default;
package/lib/express.js DELETED
@@ -1,120 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- const grant_1 = __importDefault(require("grant"));
7
- const express_session_1 = __importDefault(require("express-session"));
8
- const commons_1 = require("@feathersjs/commons");
9
- const express_1 = require("@feathersjs/express");
10
- const grantInstance = grant_1.default.express();
11
- const debug = (0, commons_1.createDebug)('@feathersjs/authentication-oauth/express');
12
- exports.default = (options) => {
13
- return (feathersApp) => {
14
- const { authService, linkStrategy } = options;
15
- const app = feathersApp;
16
- const config = app.get('grant');
17
- if (!config) {
18
- debug('No grant configuration found, skipping Express oAuth setup');
19
- return;
20
- }
21
- const { prefix } = config.defaults;
22
- const expressSession = options.expressSession ||
23
- (0, express_session_1.default)({
24
- secret: Math.random().toString(36).substring(7),
25
- saveUninitialized: true,
26
- resave: true
27
- });
28
- const grantApp = grantInstance(config);
29
- const authApp = (0, express_1.original)();
30
- authApp.use(expressSession);
31
- authApp.get('/:name', (req, _res, next) => {
32
- const { feathers_token, redirect, ...query } = req.query;
33
- if (feathers_token) {
34
- debug('Got feathers_token query parameter to link accounts', feathers_token);
35
- req.session.accessToken = feathers_token;
36
- }
37
- req.session.redirect = redirect;
38
- req.session.query = query;
39
- req.session.headers = req.headers;
40
- if (typeof req.session.save === 'function') {
41
- req.session.save((err) => {
42
- if (err) {
43
- next(`Error storing session: ${err}`);
44
- }
45
- else {
46
- next();
47
- }
48
- });
49
- }
50
- else {
51
- next();
52
- }
53
- });
54
- authApp.get('/:name/authenticate', async (req, res, next) => {
55
- const { name } = req.params;
56
- const { accessToken, grant, query = {}, redirect, headers } = req.session;
57
- const service = app.defaultAuthentication(authService);
58
- const [strategy] = service.getStrategies(name);
59
- const params = {
60
- ...req.feathers,
61
- authStrategies: [name],
62
- authentication: accessToken
63
- ? {
64
- strategy: linkStrategy,
65
- accessToken
66
- }
67
- : null,
68
- query,
69
- redirect,
70
- headers
71
- };
72
- const sendResponse = async (data) => {
73
- try {
74
- const redirect = await strategy.getRedirect(data, params);
75
- if (redirect !== null) {
76
- res.redirect(redirect);
77
- }
78
- else if (data instanceof Error) {
79
- throw data;
80
- }
81
- else {
82
- res.json(data);
83
- }
84
- }
85
- catch (error) {
86
- debug('oAuth error', error);
87
- next(error);
88
- }
89
- };
90
- try {
91
- const payload = config.defaults.transport === 'session' ? grant.response : req.query;
92
- const authentication = {
93
- strategy: name,
94
- ...payload
95
- };
96
- await new Promise((resolve, reject) => {
97
- if (req.session.destroy) {
98
- req.session.destroy((err) => (err ? reject(err) : resolve()));
99
- }
100
- else {
101
- req.session = null;
102
- resolve();
103
- }
104
- });
105
- debug(`Calling ${authService}.create authentication with strategy ${name}`);
106
- const authResult = await service.create(authentication, params);
107
- debug('Successful oAuth authentication, sending response');
108
- await sendResponse(authResult);
109
- }
110
- catch (error) {
111
- debug('Received oAuth authentication error', error.stack);
112
- await sendResponse(error);
113
- }
114
- });
115
- authApp.use(grantApp);
116
- app.set('grant', grantApp.config);
117
- app.use(prefix, authApp);
118
- };
119
- };
120
- //# sourceMappingURL=express.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"express.js","sourceRoot":"","sources":["../src/express.ts"],"names":[],"mappings":"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"}