Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions lib/errors/oauth-error.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import * as statuses from 'statuses';

export class OAuthError extends Error {
// eslint-disable-next-line import/prefer-default-export
export class OAuthError extends Error implements Record<string, any> {
code: any;

status: any;

statusCode: any;

constructor(messageOrError: string | Error, properties: any = {}) {
super();
let message =
Expand All @@ -16,16 +20,21 @@ export class OAuthError extends Error {
if (error) {
props.inner = error;
}
if (!message) {
message = statuses[props.code];
const statusMessage = statuses[props.code];
if (!message && statusMessage) {
message = statusMessage;
}
// eslint-disable-next-line no-multi-assign
this.code = this.status = this.statusCode = props.code;
this.message = message;

const ignoreAttr = ['code', 'message'];
const me: Record<string, any> = this;
Object.keys(props)
.filter(key => !ignoreAttr.includes(key))
.forEach(key => (this[key] = props[key]));
.forEach(key => {
me[key] = props[key];
});

Error.captureStackTrace(this, OAuthError);
}
Expand Down
24 changes: 18 additions & 6 deletions lib/grant-types/abstract-grant-type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,14 @@ import { Request } from '../request';
import * as tokenUtil from '../utils/token-util';
import * as is from '../validator/is';

// eslint-disable-next-line import/prefer-default-export
export class AbstractGrantType {
accessTokenLifetime: number;

model: Model;

refreshTokenLifetime: number;

alwaysIssueNewRefreshToken: boolean;

constructor(options: any = {}) {
Expand All @@ -32,11 +36,15 @@ export class AbstractGrantType {
* Generate access token.
*/

async generateAccessToken(client?: Client, user?: User, scope?: string) {
async generateAccessToken(
client: Client,
user: User,
scope: string | undefined,
) {
if (this.model.generateAccessToken) {
const token = await this.model.generateAccessToken(client, user, scope);

return token ? token : tokenUtil.GenerateRandomToken();
return token || tokenUtil.GenerateRandomToken();
}

return tokenUtil.GenerateRandomToken();
Expand All @@ -46,11 +54,15 @@ export class AbstractGrantType {
* Generate refresh token.
*/

async generateRefreshToken(client?: Client, user?: User, scope?: string) {
async generateRefreshToken(
client: Client,
user: User,
scope: string | undefined,
) {
if (this.model.generateRefreshToken) {
const token = await this.model.generateRefreshToken(client, user, scope);

return token ? token : tokenUtil.GenerateRandomToken();
return token || tokenUtil.GenerateRandomToken();
}

return tokenUtil.GenerateRandomToken();
Expand Down Expand Up @@ -80,7 +92,7 @@ export class AbstractGrantType {
* Get scope from the request body.
*/

getScope(request: Request) {
static getScope(request: Request) {
if (!is.nqschar(request.body.scope)) {
throw new InvalidArgumentError('Invalid parameter: `scope`');
}
Expand All @@ -91,7 +103,7 @@ export class AbstractGrantType {
/**
* Validate requested scope.
*/
async validateScope(user: User, client: Client, scope: string) {
async validateScope(user: User, client: Client, scope: string | undefined) {
if (this.model.validateScope) {
const validatedScope = await this.model.validateScope(
user,
Expand Down
3 changes: 2 additions & 1 deletion lib/grant-types/authorization-code-grant-type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { AuthorizationCode, Client, Token, User } from '../interfaces';
import { Request } from '../request';
import * as is from '../validator/is';

// eslint-disable-next-line import/prefer-default-export
export class AuthorizationCodeGrantType extends AbstractGrantType {
constructor(options: any = {}) {
super(options);
Expand Down Expand Up @@ -180,7 +181,7 @@ export class AuthorizationCodeGrantType extends AbstractGrantType {
user: User,
client: Client,
authorizationCode: string,
scope: string,
scope: string | undefined,
) {
const accessScope = await this.validateScope(user, client, scope);
const accessToken = await this.generateAccessToken(client, user, scope);
Expand Down
5 changes: 3 additions & 2 deletions lib/grant-types/client-credentials-grant-type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { InvalidArgumentError, InvalidGrantError } from '../errors';
import { Client, Token, User } from '../interfaces';
import { Request } from '../request';

// eslint-disable-next-line import/prefer-default-export
export class ClientCredentialsGrantType extends AbstractGrantType {
constructor(options: any = {}) {
super(options);
Expand Down Expand Up @@ -38,7 +39,7 @@ export class ClientCredentialsGrantType extends AbstractGrantType {
throw new InvalidArgumentError('Missing parameter: `client`');
}

const scope = this.getScope(request);
const scope = AbstractGrantType.getScope(request);
const user = await this.getUserFromClient(client);

return this.saveToken(user, client, scope);
Expand All @@ -63,7 +64,7 @@ export class ClientCredentialsGrantType extends AbstractGrantType {
* Save token.
*/

async saveToken(user: User, client: Client, scope: string) {
async saveToken(user: User, client: Client, scope: string | undefined) {
const accessScope = await this.validateScope(user, client, scope);
const accessToken = await this.generateAccessToken(client, user, scope);
const accessTokenExpiresAt = this.getAccessTokenExpiresAt();
Expand Down
5 changes: 4 additions & 1 deletion lib/grant-types/implicit-grant-type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@ import { InvalidArgumentError } from '../errors';
import { Client, Token, User } from '../interfaces';
import { Request } from '../request';

// eslint-disable-next-line import/prefer-default-export
export class ImplicitGrantType extends AbstractGrantType {
scope: string;

user: User;

constructor(options: any = {}) {
super(options);

Expand Down Expand Up @@ -47,7 +50,7 @@ export class ImplicitGrantType extends AbstractGrantType {
* Save token.
*/

async saveToken(user: User, client: Client, scope: string) {
async saveToken(user: User, client: Client, scope: string | undefined) {
const validatedScope = await this.validateScope(user, client, scope);
const accessToken = await this.generateAccessToken(client, user, scope);
const accessTokenExpiresAt = this.getAccessTokenExpiresAt();
Expand Down
7 changes: 4 additions & 3 deletions lib/grant-types/password-grant-type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { Client, Token, User } from '../interfaces';
import { Request } from '../request';
import * as is from '../validator/is';

// eslint-disable-next-line import/prefer-default-export
export class PasswordGrantType extends AbstractGrantType {
constructor(options: any = {}) {
super(options);
Expand Down Expand Up @@ -35,7 +36,7 @@ export class PasswordGrantType extends AbstractGrantType {
* @see https://tools.ietf.org/html/rfc6749#section-4.3.2
*/

async handle(request, client) {
async handle(request: Request, client: Client) {
if (!request) {
throw new InvalidArgumentError('Missing parameter: `request`');
}
Expand All @@ -44,7 +45,7 @@ export class PasswordGrantType extends AbstractGrantType {
throw new InvalidArgumentError('Missing parameter: `client`');
}

const scope = this.getScope(request);
const scope = AbstractGrantType.getScope(request);
const user = await this.getUser(request);

return this.saveToken(user, client, scope);
Expand Down Expand Up @@ -88,7 +89,7 @@ export class PasswordGrantType extends AbstractGrantType {
* Save token.
*/

async saveToken(user: User, client: Client, scope: string) {
async saveToken(user: User, client: Client, scope: string | undefined) {
const accessScope = await this.validateScope(user, client, scope);
const accessToken = await this.generateAccessToken(client, user, scope);
const refreshToken = await this.generateRefreshToken(client, user, scope);
Expand Down
3 changes: 2 additions & 1 deletion lib/grant-types/refresh-token-grant-type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { Client, RefreshToken, User } from '../interfaces';
import { Request } from '../request';
import * as is from '../validator/is';

// eslint-disable-next-line import/prefer-default-export
export class RefreshTokenGrantType extends AbstractGrantType {
constructor(options: any = {}) {
super(options);
Expand Down Expand Up @@ -134,7 +135,7 @@ export class RefreshTokenGrantType extends AbstractGrantType {
* Save token.
*/

async saveToken(user: User, client: Client, scope: string) {
async saveToken(user: User, client: Client, scope: string | undefined) {
const accessToken = await this.generateAccessToken(client, user, scope);
const refreshToken = await this.generateRefreshToken(client, user, scope);
const accessTokenExpiresAt = this.getAccessTokenExpiresAt();
Expand Down
23 changes: 15 additions & 8 deletions lib/handlers/authenticate-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,22 @@ import {
ServerError,
UnauthorizedRequestError,
} from '../errors';
import { Model, Token } from '../interfaces';
import { Request } from '../request';
import { Response } from '../response';
import { Token, Model } from '../interfaces';

// eslint-disable-next-line import/prefer-default-export
export class AuthenticateHandler {
addAcceptedScopesHeader: any;

addAuthorizedScopesHeader: any;

allowBearerTokensInQueryString: any;

model: Model;

scope: any;

constructor(options: any = {}) {
if (!options.model) {
throw new InvalidArgumentError('Missing parameter: `model`');
Expand Down Expand Up @@ -77,7 +83,7 @@ export class AuthenticateHandler {
try {
let token = await this.getTokenFromRequest(request);
token = await this.getAccessToken(token);
this.validateAccessToken(token);
AuthenticateHandler.validateAccessToken(token);
if (this.scope) {
await this.verifyScope(token);
}
Expand Down Expand Up @@ -121,15 +127,15 @@ export class AuthenticateHandler {
}

if (headerToken) {
return this.getTokenFromRequestHeader(request);
return AuthenticateHandler.getTokenFromRequestHeader(request);
}

if (queryToken) {
return this.getTokenFromRequestQuery(request);
}

if (bodyToken) {
return this.getTokenFromRequestBody(request);
return AuthenticateHandler.getTokenFromRequestBody(request);
}

throw new UnauthorizedRequestError(
Expand All @@ -143,7 +149,7 @@ export class AuthenticateHandler {
* @see http://tools.ietf.org/html/rfc6750#section-2.1
*/

getTokenFromRequestHeader(request: Request) {
static getTokenFromRequestHeader(request: Request) {
const token = request.get('Authorization');
const matches = token.match(/Bearer\s(\S+)/);

Expand Down Expand Up @@ -189,7 +195,7 @@ export class AuthenticateHandler {
* @see http://tools.ietf.org/html/rfc6750#section-2.2
*/

getTokenFromRequestBody(request: Request) {
static getTokenFromRequestBody(request: Request) {
if (request.method === 'GET') {
throw new InvalidRequestError(
'Invalid request: token may not be passed in the body when using the GET verb',
Expand Down Expand Up @@ -228,7 +234,7 @@ export class AuthenticateHandler {
* Validate access token.
*/

validateAccessToken(accessToken: Token) {
static validateAccessToken(accessToken: Token) {
if (!(accessToken.accessTokenExpiresAt instanceof Date)) {
throw new ServerError(
'Server error: `accessTokenExpiresAt` must be a Date instance',
Expand Down Expand Up @@ -266,7 +272,8 @@ export class AuthenticateHandler {
response.set('X-Accepted-OAuth-Scopes', this.scope);
}

if (this.scope && this.addAuthorizedScopesHeader) {
// Or throw when accessToken.scope is not set?
if (this.scope && this.addAuthorizedScopesHeader && accessToken.scope) {
response.set('X-OAuth-Scopes', accessToken.scope);
}
}
Expand Down
Loading