Skip to content

Commit

Permalink
feat(authentication-oauth): Allow dynamic oAuth redirect (#2469)
Browse files Browse the repository at this point in the history
  • Loading branch information
daffl authored Oct 13, 2021
1 parent 27eb7b3 commit b7143d4
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 3 deletions.
7 changes: 5 additions & 2 deletions packages/authentication-oauth/src/express.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ declare module 'express-session' {
accessToken: string;
query: { [key: string]: any };
grant: { [key: string]: any };
headers: { [key: string]: any };
}
}

Expand Down Expand Up @@ -54,13 +55,14 @@ export default (options: OauthSetupSettings) => {
}
req.session.redirect = redirect as string;
req.session.query = query;
req.session.headers = req.headers;

next()
});

authApp.get('/:name/authenticate', async (req: Request, res: Response, next: NextFunction) => {
const { name } = req.params ;
const { accessToken, grant, query = {}, redirect } = req.session;
const { accessToken, grant, query = {}, redirect, headers } = req.session;
const service = app.defaultAuthentication(authService);
const [ strategy ] = service.getStrategies(name) as OAuthStrategy[];
const params = {
Expand All @@ -71,7 +73,8 @@ export default (options: OauthSetupSettings) => {
accessToken
} : null,
query,
redirect
redirect,
headers
};
const sendResponse = async (data: AuthenticationResult|Error) => {
try {
Expand Down
19 changes: 18 additions & 1 deletion packages/authentication-oauth/src/strategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,26 @@ export class OAuthStrategy extends AuthenticationBaseStrategy {
return null;
}

async getAllowedOrigin (params?: Params) {
const { redirect, origins } = this.authentication.configuration.oauth;

if (Array.isArray(origins)) {
const referer = params?.headers?.referer || '';
const allowedOrigin = origins.find(current => referer.toLowerCase().startsWith(current.toLowerCase()));

if(!allowedOrigin) {
throw new NotAuthenticated(`Referer "${referer || '[header not available]'}" not allowed.`);
}

return allowedOrigin;
}

return redirect;
}

async getRedirect (data: AuthenticationResult|Error, params?: Params): Promise<string | null> {
const queryRedirect = (params && params.redirect) || '';
const { redirect } = this.authentication.configuration.oauth;
const redirect = await this.getAllowedOrigin(params);

if (!redirect) {
return null;
Expand Down
37 changes: 37 additions & 0 deletions packages/authentication-oauth/test/strategy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,43 @@ describe('@feathersjs/authentication-oauth/strategy', () => {
assert.equal(redirect, '/#dashboard?access_token=testing');
});

it('getRedirect with referrer and allowed origins (#2430)', async () => {
app.get('authentication').oauth.origins = [
'https://feathersjs.com',
'https://feathers.cloud'
];

let redirect = await strategy.getRedirect({ accessToken: 'testing' }, {
headers: {
referer: 'https://feathersjs.com/somewhere'
}
});
assert.equal(redirect, 'https://feathersjs.com#access_token=testing');

redirect = await strategy.getRedirect({ accessToken: 'testing' }, {
headers: {
referer: 'HTTPS://feathers.CLOUD'
}
});
assert.equal(redirect, 'https://feathers.cloud#access_token=testing');

redirect = await strategy.getRedirect({ accessToken: 'testing' }, {
redirect: '/home',
headers: {
referer: 'https://feathersjs.com/somewhere'
}
});
assert.equal(redirect, 'https://feathersjs.com/home#access_token=testing');

await assert.rejects(() => strategy.getRedirect({ accessToken: 'testing' }, {
headers: {
referer: 'https://example.com'
}
}), {
message: 'Referer "https://example.com" not allowed.'
});
});

describe('authenticate', () => {
it('with new user', async () => {
const authResult = await strategy.authenticate({
Expand Down
10 changes: 10 additions & 0 deletions packages/authentication/src/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,16 @@ export class AuthenticationBase {
.filter(current => !!current);
}

/**
* Returns a single strategy by name
*
* @param name The strategy name
* @returns The authentication strategy or undefined
*/
getStrategy (name: string) {
return this.strategies[name];
}

/**
* Create a new access token with payload and options.
*
Expand Down
6 changes: 6 additions & 0 deletions packages/authentication/test/core.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,12 @@ describe('authentication/core', () => {
assert.strictEqual(invalid.length, 2, 'Filtered out invalid strategies');
});

it('getStrategy', () => {
const first = auth.getStrategy('first');

assert.ok(first);
});

it('calls setName, setApplication and setAuthentication if available', () => {
const [ first ] = auth.getStrategies('first') as [ Strategy1 ];

Expand Down

0 comments on commit b7143d4

Please sign in to comment.