Skip to content

Converted to typescript (working code) #102

Open
@Uzlopak

Description

@Uzlopak

This middleware is actually very simple. So ported it to typescript.

Install latest oauth2-server as separate package and avoid using this obsolete package.

import { Promise } from "bluebird";
import {
	Request,
	Response,
	AuthenticateOptions,
	AuthorizationCode,
	AuthorizeOptions,
	ServerOptions,
	TokenOptions,
	Token,
	InvalidArgumentError,
	OAuthError,
	UnauthorizedRequestError,
} from "oauth2-server";
import * as NodeOAuthServer from "oauth2-server";
import {
	RequestHandler,
	Response as ExpressResponse,
	Request as ExpressRequest,
	NextFunction,
} from "express";

interface IOAuthServerOptions extends
	ServerOptions {
	useErrorHandler?: boolean;
	continueMiddleware?: boolean;
}

export function OAuthServer(options?: IOAuthServerOptions): void {
	options = options || {} as IOAuthServerOptions;

	if (!options.model) {
		throw new InvalidArgumentError('Missing parameter: `model`');
	}

	this.useErrorHandler = options.useErrorHandler ? true : false;
	delete options.useErrorHandler;

	this.continueMiddleware = options.continueMiddleware ? true : false;
	delete options.continueMiddleware;

	this.server = new NodeOAuthServer(options);
}

/**
 * Authentication Middleware.
 *
 * Returns a middleware that will validate a token.
 *
 * (See: https://tools.ietf.org/html/rfc6749#section-7)
 */

OAuthServer.prototype.authenticate = function (options: AuthenticateOptions): any {
	const that = this;

	return function (req: ExpressRequest, res: ExpressResponse, next: NextFunction): any {
		const request = new Request(req);
		const response = new Response(res);
		return Promise.bind(that)
			.then(function (): Promise<Token> {

				return (this.server as NodeOAuthServer).authenticate(request, response, options);
			})
			.tap(function (token: Token): void {
				(res as any).locals.oauth = { token };
				next();
			})
			.catch(function (e: Error): void {
				return handleError.call(this, e, req, res, null, next);
			});
	};
};

/**
 * Authorization Middleware.
 *
 * Returns a middleware that will authorize a client to request tokens.
 *
 * (See: https://tools.ietf.org/html/rfc6749#section-3.1)
 */

OAuthServer.prototype.authorize = function (options: AuthorizeOptions): RequestHandler {
	const that = this;

	return function (req: ExpressRequest, res: ExpressResponse, next: NextFunction): any {
		const request = new Request(req);
		const response = new Response(res);

		return Promise.bind(that)
			.then(function (): Promise<AuthorizationCode> {
				return (this.server as NodeOAuthServer).authorize(request, response, options);
			})
			.tap(function (code: AuthorizationCode): void {
				(res as any).locals.oauth = { code };
				if (this.continueMiddleware) {
					next();
				}
			})
			.then(function (): void {
				return handleResponse.call(this, req, res, response);
			})
			.catch(function (e: Error): void {
				return handleError.call(this, e, req, res, response, next);
			});
	};
};

/**
 * Grant Middleware.
 *
 * Returns middleware that will grant tokens to valid requests.
 *
 * (See: https://tools.ietf.org/html/rfc6749#section-3.2)
 */
OAuthServer.prototype.token = function (options: TokenOptions): RequestHandler {
	const that = this;

	return function (req: ExpressRequest, res: ExpressResponse, next: NextFunction): Promise<void> {
		const request = new Request(req);
		const response = new Response(res);

		return Promise.bind(that)
			.then(function (): Promise<Token> {
				return (this.server as NodeOAuthServer).token(request, response, options);
			})
			.tap(function (token: Token): void {
				(res as any).locals.oauth = { token };
				if (this.continueMiddleware) {
					next();
				}
			})
			.then(function (): void {
				return handleResponse.call(this, req, res, response);
			})
			.catch(function (e: Error): void {
				return handleError.call(this, e, req, res, response, next);
			});
	};
};

const handleResponse = function (req: ExpressRequest, res: ExpressResponse, response: Response): void {

	if (response.status === 302) {
		const location = response.headers.location;
		delete response.headers.location;
		res.set(response.headers);
		res.redirect(location);
	} else {
		res.set(response.headers);
		res.status(response.status).send(response.body);
	}
};

const handleError = function (e: OAuthError, req: ExpressRequest, res: ExpressResponse, response: Response, next: NextFunction): void {

	if (this.useErrorHandler === true) {
		next(e);
	} else {
		if (response) {
			res.set(response.headers);
		}

		res.status(e.code);

		if (e instanceof UnauthorizedRequestError) {
			res.send();
			return;
		}

		res.send({ error: e.name, error_description: e.message });
	}
};

export default OAuthServer;

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions