@feathersjs/authentication-oauth 5.0.0-pre.9 → 5.0.1
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/CHANGELOG.md +151 -185
- package/LICENSE +1 -1
- package/README.md +2 -2
- package/lib/index.d.ts +1 -3
- package/lib/index.js +22 -56
- package/lib/index.js.map +1 -1
- package/lib/service.d.ts +36 -0
- package/lib/service.js +143 -0
- package/lib/service.js.map +1 -0
- package/lib/strategy.d.ts +4 -3
- package/lib/strategy.js +95 -119
- package/lib/strategy.js.map +1 -1
- package/lib/utils.d.ts +13 -4
- package/lib/utils.js +90 -5
- package/lib/utils.js.map +1 -1
- package/package.json +32 -23
- package/src/index.ts +35 -66
- package/src/service.ts +179 -0
- package/src/strategy.ts +97 -80
- package/src/utils.ts +118 -12
- package/lib/express.d.ts +0 -16
- package/lib/express.js +0 -114
- package/lib/express.js.map +0 -1
- package/src/express.ts +0 -128
package/lib/utils.d.ts
CHANGED
|
@@ -1,8 +1,17 @@
|
|
|
1
|
-
import { RequestHandler } from 'express';
|
|
2
|
-
import {
|
|
1
|
+
import type { RequestHandler } from 'express';
|
|
2
|
+
import type { Middleware } from '@feathersjs/koa';
|
|
3
|
+
import type { ServiceOptions } from '@feathersjs/feathers';
|
|
4
|
+
import '@feathersjs/koa';
|
|
5
|
+
import '@feathersjs/express';
|
|
6
|
+
import { AuthenticationService } from '@feathersjs/authentication';
|
|
7
|
+
import { GrantConfig } from 'grant';
|
|
3
8
|
export interface OauthSetupSettings {
|
|
9
|
+
linkStrategy: string;
|
|
4
10
|
authService?: string;
|
|
5
11
|
expressSession?: RequestHandler;
|
|
6
|
-
|
|
12
|
+
koaSession?: Middleware;
|
|
7
13
|
}
|
|
8
|
-
export declare const
|
|
14
|
+
export declare const getGrantConfig: (service: AuthenticationService) => GrantConfig;
|
|
15
|
+
export declare const setExpressParams: RequestHandler;
|
|
16
|
+
export declare const setKoaParams: Middleware;
|
|
17
|
+
export declare const authenticationServiceOptions: (service: AuthenticationService, settings: OauthSetupSettings) => ServiceOptions;
|
package/lib/utils.js
CHANGED
|
@@ -1,9 +1,94 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
6
|
+
exports.authenticationServiceOptions = exports.setKoaParams = exports.setExpressParams = exports.getGrantConfig = void 0;
|
|
7
|
+
require("@feathersjs/koa");
|
|
8
|
+
require("@feathersjs/express");
|
|
9
|
+
const cookie_session_1 = __importDefault(require("cookie-session"));
|
|
10
|
+
const koa_session_1 = __importDefault(require("koa-session"));
|
|
11
|
+
const lodash_1 = require("lodash");
|
|
12
|
+
const getGrantConfig = (service) => {
|
|
13
|
+
const { app, configuration: { oauth } } = service;
|
|
14
|
+
// Set up all the defaults
|
|
15
|
+
const port = app.get('port');
|
|
16
|
+
let host = app.get('host');
|
|
17
|
+
let protocol = 'https';
|
|
18
|
+
// Development environments commonly run on HTTP with an extended port
|
|
19
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
20
|
+
protocol = 'http';
|
|
21
|
+
if (String(port) !== '80') {
|
|
22
|
+
host += `:${port}`;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
const grant = (0, lodash_1.defaultsDeep)({}, (0, lodash_1.omit)(oauth, ['redirect', 'origins']), {
|
|
26
|
+
defaults: {
|
|
27
|
+
prefix: '/oauth',
|
|
28
|
+
origin: `${protocol}://${host}`,
|
|
29
|
+
transport: 'state',
|
|
30
|
+
response: ['tokens', 'raw', 'profile']
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
const getUrl = (url) => {
|
|
34
|
+
const { defaults } = grant;
|
|
35
|
+
return `${defaults.origin}${defaults.prefix}/${url}`;
|
|
36
|
+
};
|
|
37
|
+
(0, lodash_1.each)(grant, (value, name) => {
|
|
38
|
+
if (name !== 'defaults') {
|
|
39
|
+
value.redirect_uri = value.redirect_uri || getUrl(`${name}/callback`);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
return grant;
|
|
43
|
+
};
|
|
44
|
+
exports.getGrantConfig = getGrantConfig;
|
|
45
|
+
const setExpressParams = (req, res, next) => {
|
|
46
|
+
var _a;
|
|
47
|
+
(_a = req.session).destroy || (_a.destroy = () => {
|
|
48
|
+
req.session = null;
|
|
49
|
+
});
|
|
50
|
+
req.feathers = {
|
|
51
|
+
...req.feathers,
|
|
52
|
+
session: req.session,
|
|
53
|
+
state: res.locals
|
|
54
|
+
};
|
|
55
|
+
next();
|
|
56
|
+
};
|
|
57
|
+
exports.setExpressParams = setExpressParams;
|
|
58
|
+
const setKoaParams = async (ctx, next) => {
|
|
59
|
+
var _a;
|
|
60
|
+
(_a = ctx.session).destroy || (_a.destroy = () => {
|
|
61
|
+
ctx.session = null;
|
|
62
|
+
});
|
|
63
|
+
ctx.feathers = {
|
|
64
|
+
...ctx.feathers,
|
|
65
|
+
session: ctx.session,
|
|
66
|
+
state: ctx.state
|
|
67
|
+
};
|
|
68
|
+
await next();
|
|
69
|
+
};
|
|
70
|
+
exports.setKoaParams = setKoaParams;
|
|
71
|
+
const authenticationServiceOptions = (service, settings) => {
|
|
72
|
+
const { secret } = service.configuration;
|
|
73
|
+
const koaApp = service.app;
|
|
74
|
+
if (koaApp.context) {
|
|
75
|
+
koaApp.keys = [secret];
|
|
76
|
+
const { koaSession = (0, koa_session_1.default)({ key: 'feathers.oauth' }, koaApp) } = settings;
|
|
77
|
+
return {
|
|
78
|
+
koa: {
|
|
79
|
+
before: [koaSession, exports.setKoaParams]
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
const { expressSession = (0, cookie_session_1.default)({
|
|
84
|
+
name: 'feathers.oauth',
|
|
85
|
+
keys: [secret]
|
|
86
|
+
}) } = settings;
|
|
87
|
+
return {
|
|
88
|
+
express: {
|
|
89
|
+
before: [expressSession, exports.setExpressParams]
|
|
90
|
+
}
|
|
91
|
+
};
|
|
7
92
|
};
|
|
8
|
-
exports.
|
|
93
|
+
exports.authenticationServiceOptions = authenticationServiceOptions;
|
|
9
94
|
//# sourceMappingURL=utils.js.map
|
package/lib/utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@feathersjs/authentication-oauth",
|
|
3
3
|
"description": "oAuth 1 and 2 authentication for Feathers. Powered by Grant.",
|
|
4
|
-
"version": "5.0.
|
|
4
|
+
"version": "5.0.1",
|
|
5
5
|
"homepage": "https://feathersjs.com",
|
|
6
6
|
"main": "lib/",
|
|
7
7
|
"types": "lib/",
|
|
@@ -16,7 +16,8 @@
|
|
|
16
16
|
},
|
|
17
17
|
"repository": {
|
|
18
18
|
"type": "git",
|
|
19
|
-
"url": "git://github.com/feathersjs/feathers.git"
|
|
19
|
+
"url": "git://github.com/feathersjs/feathers.git",
|
|
20
|
+
"directory": "packages/authentication-oauth"
|
|
20
21
|
},
|
|
21
22
|
"author": {
|
|
22
23
|
"name": "Feathers contributors",
|
|
@@ -42,7 +43,8 @@
|
|
|
42
43
|
"scripts": {
|
|
43
44
|
"start": "ts-node test/app",
|
|
44
45
|
"prepublish": "npm run compile",
|
|
45
|
-
"
|
|
46
|
+
"pack": "npm pack --pack-destination ../generators/test/build",
|
|
47
|
+
"compile": "shx rm -rf lib/ && tsc && npm run pack",
|
|
46
48
|
"test": "mocha --config ../../.mocharc.json --recursive test/**.test.ts test/**/*.test.ts"
|
|
47
49
|
},
|
|
48
50
|
"directories": {
|
|
@@ -52,27 +54,34 @@
|
|
|
52
54
|
"access": "public"
|
|
53
55
|
},
|
|
54
56
|
"dependencies": {
|
|
55
|
-
"@feathersjs/authentication": "^5.0.
|
|
56
|
-
"@feathersjs/commons": "^5.0.
|
|
57
|
-
"@feathersjs/errors": "^5.0.
|
|
58
|
-
"@feathersjs/express": "^5.0.
|
|
59
|
-
"@feathersjs/feathers": "^5.0.
|
|
60
|
-
"
|
|
61
|
-
"
|
|
62
|
-
"
|
|
57
|
+
"@feathersjs/authentication": "^5.0.1",
|
|
58
|
+
"@feathersjs/commons": "^5.0.1",
|
|
59
|
+
"@feathersjs/errors": "^5.0.1",
|
|
60
|
+
"@feathersjs/express": "^5.0.1",
|
|
61
|
+
"@feathersjs/feathers": "^5.0.1",
|
|
62
|
+
"@feathersjs/koa": "^5.0.1",
|
|
63
|
+
"@feathersjs/schema": "^5.0.1",
|
|
64
|
+
"cookie-session": "^2.0.0",
|
|
65
|
+
"grant": "^5.4.21",
|
|
66
|
+
"koa-session": "^6.4.0",
|
|
67
|
+
"lodash": "^4.17.21",
|
|
68
|
+
"qs": "^6.11.1"
|
|
63
69
|
},
|
|
64
70
|
"devDependencies": {
|
|
65
|
-
"@feathersjs/memory": "^5.0.
|
|
66
|
-
"@types/
|
|
67
|
-
"@types/express
|
|
68
|
-
"@types/
|
|
69
|
-
"@types/
|
|
70
|
-
"@types/
|
|
71
|
-
"
|
|
72
|
-
"
|
|
73
|
-
"
|
|
74
|
-
"
|
|
75
|
-
"
|
|
71
|
+
"@feathersjs/memory": "^5.0.1",
|
|
72
|
+
"@types/cookie-session": "^2.0.44",
|
|
73
|
+
"@types/express": "^4.17.17",
|
|
74
|
+
"@types/koa-session": "^5.10.6",
|
|
75
|
+
"@types/lodash": "^4.14.191",
|
|
76
|
+
"@types/mocha": "^10.0.1",
|
|
77
|
+
"@types/node": "^18.14.6",
|
|
78
|
+
"@types/tough-cookie": "^4.0.2",
|
|
79
|
+
"axios": "^1.3.4",
|
|
80
|
+
"mocha": "^10.2.0",
|
|
81
|
+
"shx": "^0.3.4",
|
|
82
|
+
"tough-cookie": "^4.1.2",
|
|
83
|
+
"ts-node": "^10.9.1",
|
|
84
|
+
"typescript": "^4.9.5"
|
|
76
85
|
},
|
|
77
|
-
"gitHead": "
|
|
86
|
+
"gitHead": "18b7f4ab0a8075572a81d78956ba1205a9795c91"
|
|
78
87
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,80 +1,49 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import { createDebug } from '@feathersjs/commons';
|
|
5
|
-
import { Application } from '@feathersjs/feathers';
|
|
6
|
-
import { OAuthStrategy, OAuthProfile } from './strategy';
|
|
7
|
-
import { default as setupExpress } from './express';
|
|
8
|
-
import { OauthSetupSettings, getDefaultSettings } from './utils';
|
|
1
|
+
import { Application } from '@feathersjs/feathers'
|
|
2
|
+
import { createDebug } from '@feathersjs/commons'
|
|
3
|
+
import { resolveDispatch } from '@feathersjs/schema'
|
|
9
4
|
|
|
10
|
-
|
|
5
|
+
import { OAuthStrategy, OAuthProfile } from './strategy'
|
|
6
|
+
import { redirectHook, OAuthService } from './service'
|
|
7
|
+
import { getGrantConfig, authenticationServiceOptions, OauthSetupSettings } from './utils'
|
|
11
8
|
|
|
12
|
-
|
|
9
|
+
const debug = createDebug('@feathersjs/authentication-oauth')
|
|
13
10
|
|
|
14
|
-
export
|
|
15
|
-
const service = app.defaultAuthentication ? app.defaultAuthentication(options.authService) : null;
|
|
11
|
+
export { OauthSetupSettings, OAuthStrategy, OAuthProfile }
|
|
16
12
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
const { oauth } = service.configuration;
|
|
22
|
-
|
|
23
|
-
if (!oauth) {
|
|
24
|
-
debug('No oauth configuration found in authentication configuration. Skipping oAuth setup.');
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const { strategyNames } = service;
|
|
29
|
-
|
|
30
|
-
// Set up all the defaults
|
|
31
|
-
const { prefix = '/oauth' } = oauth.defaults || {};
|
|
32
|
-
const port = app.get('port');
|
|
33
|
-
let host = app.get('host');
|
|
34
|
-
let protocol = 'https';
|
|
13
|
+
export const oauth =
|
|
14
|
+
(settings: Partial<OauthSetupSettings> = {}) =>
|
|
15
|
+
(app: Application) => {
|
|
16
|
+
const authService = app.defaultAuthentication ? app.defaultAuthentication(settings.authService) : null
|
|
35
17
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
host += `:${port}`;
|
|
18
|
+
if (!authService) {
|
|
19
|
+
throw new Error(
|
|
20
|
+
'An authentication service must exist before registering @feathersjs/authentication-oauth'
|
|
21
|
+
)
|
|
41
22
|
}
|
|
42
|
-
}
|
|
43
23
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
origin: `${protocol}://${host}`,
|
|
48
|
-
transport: 'session',
|
|
49
|
-
response: ['tokens', 'raw', 'profile']
|
|
24
|
+
if (!authService.configuration.oauth) {
|
|
25
|
+
debug('No oauth configuration found in authentication configuration. Skipping oAuth setup.')
|
|
26
|
+
return
|
|
50
27
|
}
|
|
51
|
-
}, omit(oauth, 'redirect'));
|
|
52
|
-
|
|
53
|
-
const getUrl = (url: string) => {
|
|
54
|
-
const { defaults } = grant;
|
|
55
|
-
return `${defaults.origin}${prefix}/${url}`;
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
each(grant, (value, name) => {
|
|
59
|
-
if (name !== 'defaults') {
|
|
60
|
-
value.callback = value.callback || getUrl(`${name}/authenticate`);
|
|
61
|
-
value.redirect_uri = value.redirect_uri || getUrl(`${name}/callback`);
|
|
62
28
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
}
|
|
29
|
+
const oauthOptions = {
|
|
30
|
+
linkStrategy: 'jwt',
|
|
31
|
+
...settings
|
|
67
32
|
}
|
|
68
|
-
});
|
|
69
33
|
|
|
70
|
-
|
|
71
|
-
|
|
34
|
+
const grantConfig = getGrantConfig(authService)
|
|
35
|
+
const serviceOptions = authenticationServiceOptions(authService, oauthOptions)
|
|
36
|
+
const servicePath = `${grantConfig.defaults.prefix || 'oauth'}/:provider`
|
|
72
37
|
|
|
73
|
-
|
|
74
|
-
const options = getDefaultSettings(app, settings);
|
|
38
|
+
app.use(servicePath, new OAuthService(authService, oauthOptions), serviceOptions)
|
|
75
39
|
|
|
76
|
-
|
|
77
|
-
app.configure(setupExpress(options));
|
|
78
|
-
};
|
|
40
|
+
const oauthService = app.service(servicePath)
|
|
79
41
|
|
|
80
|
-
|
|
42
|
+
oauthService.hooks({
|
|
43
|
+
around: { all: [resolveDispatch(), redirectHook()] }
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
if (typeof oauthService.publish === 'function') {
|
|
47
|
+
app.service(servicePath).publish(() => null)
|
|
48
|
+
}
|
|
49
|
+
}
|
package/src/service.ts
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
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, headers, query = {}, redirect } = params.session
|
|
96
|
+
const strategy = this.service.getStrategy(name) as OAuthStrategy
|
|
97
|
+
const authParams = {
|
|
98
|
+
...params,
|
|
99
|
+
headers,
|
|
100
|
+
authStrategies: [name],
|
|
101
|
+
authentication: accessToken
|
|
102
|
+
? {
|
|
103
|
+
strategy: linkStrategy,
|
|
104
|
+
accessToken
|
|
105
|
+
}
|
|
106
|
+
: null,
|
|
107
|
+
query,
|
|
108
|
+
redirect
|
|
109
|
+
}
|
|
110
|
+
const payload = grant?.response || result?.session?.response || result?.state?.response || params.query
|
|
111
|
+
const authentication = {
|
|
112
|
+
strategy: name,
|
|
113
|
+
...payload
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
try {
|
|
117
|
+
debug(`Calling ${authService}.create authentication with strategy ${name}`)
|
|
118
|
+
|
|
119
|
+
const authResult = await this.service.create(authentication, authParams)
|
|
120
|
+
|
|
121
|
+
debug('Successful oAuth authentication, sending response')
|
|
122
|
+
|
|
123
|
+
const location = await strategy.getRedirect(authResult, authParams)
|
|
124
|
+
|
|
125
|
+
if (typeof params.session.destroy === 'function') {
|
|
126
|
+
await params.session.destroy()
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return {
|
|
130
|
+
...authResult,
|
|
131
|
+
location
|
|
132
|
+
}
|
|
133
|
+
} catch (error: any) {
|
|
134
|
+
const location = await strategy.getRedirect(error, authParams)
|
|
135
|
+
const e = new OAuthError(error.message, error.data, location)
|
|
136
|
+
|
|
137
|
+
if (typeof params.session.destroy === 'function') {
|
|
138
|
+
await params.session.destroy()
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
e.stack = error.stack
|
|
142
|
+
throw e
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
async find(params: OAuthParams) {
|
|
147
|
+
const { session, query, headers } = params
|
|
148
|
+
const { feathers_token, redirect, ...restQuery } = query
|
|
149
|
+
const handlerParams = {
|
|
150
|
+
...params,
|
|
151
|
+
query: restQuery
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (feathers_token) {
|
|
155
|
+
debug('Got feathers_token query parameter to link accounts', feathers_token)
|
|
156
|
+
session.accessToken = feathers_token
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
session.redirect = redirect
|
|
160
|
+
session.query = restQuery
|
|
161
|
+
session.headers = headers
|
|
162
|
+
|
|
163
|
+
return this.handler('GET', handlerParams, {})
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
async get(override: string, params: OAuthParams) {
|
|
167
|
+
const result = await this.handler('GET', params, {}, override)
|
|
168
|
+
|
|
169
|
+
if (override === 'callback') {
|
|
170
|
+
return this.authenticate(params, result)
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return result
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
async create(data: any, params: OAuthParams) {
|
|
177
|
+
return this.handler('POST', params, data)
|
|
178
|
+
}
|
|
179
|
+
}
|