import querystring, { ParsedUrlQueryInput } from "querystring"; import { parse } from "uri-js"; import { OAuthClient } from "../../entities/client.entity"; import { OAuthException } from "../../exceptions/oauth.exception"; import { RequestInterface } from "../../requests/request"; import { AbstractGrant } from "./abstract.grant"; export abstract class AbstractAuthorizedGrant extends AbstractGrant { protected makeRedirectUrl(uri: string, params: ParsedUrlQueryInput, queryDelimiter = "?") { const split = uri.includes(queryDelimiter) ? "&" : queryDelimiter; return uri + split + querystring.stringify(params); } protected getRedirectUri(request: RequestInterface, client: OAuthClient): string | undefined { let redirectUri = this.getQueryStringParameter("redirect_uri", request); if (!redirectUri) { return; } if (Array.isArray(redirectUri) && redirectUri.length === 1) { redirectUri = redirectUri[0]; } this.validateRedirectUri(redirectUri, client); return redirectUri; } private validateRedirectUri(redirectUri: any, client: OAuthClient) { if (typeof redirectUri !== "string" || redirectUri === "") { throw OAuthException.invalidRequest("redirect_uri"); } const parsed = parse(redirectUri); if (!parsed.scheme) { throw OAuthException.invalidRequest("redirect_uri"); } if (!!parsed.fragment) { throw OAuthException.invalidRequest( "redirect_uri", "Redirection endpoint must not contain url fragment based on RFC6749, section 3.1.2", ); } const redirectUriWithoutQuery = redirectUri.split("?")[0]; if (!client.redirectUris.includes(redirectUriWithoutQuery)) { throw OAuthException.invalidClient("Invalid redirect_uri"); } return redirectUri; } }