@delewis13/appauth
Version:
A general purpose OAuth client. Vendored awaiting PR merge
158 lines (140 loc) • 5.23 kB
text/typescript
/*
* Copyright 2017 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*/
import {AuthorizationRequest} from './authorization_request';
import {AuthorizationError, AuthorizationResponse} from './authorization_response';
import {AuthorizationServiceConfiguration} from './authorization_service_configuration';
import {Crypto} from './crypto_utils';
import {log} from './logger';
import {QueryStringUtils} from './query_string_utils';
import {StringMap} from './types';
/**
* This type represents a lambda that can take an AuthorizationRequest,
* and an AuthorizationResponse as arguments.
*/
export type AuthorizationListener =
(request: AuthorizationRequest,
response: AuthorizationResponse|null,
error: AuthorizationError|null) => void;
/**
* Represents a structural type holding both authorization request and response.
*/
export interface AuthorizationRequestResponse {
request: AuthorizationRequest;
response: AuthorizationResponse|null;
error: AuthorizationError|null;
}
/**
* Authorization Service notifier.
* This manages the communication of the AuthorizationResponse to the 3p client.
*/
export class AuthorizationNotifier {
private listener: AuthorizationListener|null = null;
setAuthorizationListener(listener: AuthorizationListener) {
this.listener = listener;
}
/**
* The authorization complete callback.
*/
onAuthorizationComplete(
request: AuthorizationRequest,
response: AuthorizationResponse|null,
error: AuthorizationError|null): void {
if (this.listener) {
// complete authorization request
this.listener(request, response, error);
}
}
}
// TODO(rahulrav@): add more built in parameters.
/* built in parameters. */
export const BUILT_IN_PARAMETERS = ['redirect_uri', 'client_id', 'response_type', 'state', 'scope'];
/**
* Defines the interface which is capable of handling an authorization request
* using various methods (iframe / popup / different process etc.).
*/
export abstract class AuthorizationRequestHandler {
constructor(public utils: QueryStringUtils, protected crypto: Crypto) {}
// notifier send the response back to the client.
protected notifier: AuthorizationNotifier|null = null;
/**
* A utility method to be able to build the authorization request URL.
*/
protected buildRequestUrl(
configuration: AuthorizationServiceConfiguration,
request: AuthorizationRequest) {
// build the query string
// coerce to any type for convenience
let requestMap: StringMap = {
'redirect_uri': request.redirectUri,
'client_id': request.clientId,
'response_type': request.responseType,
'state': request.state,
'scope': request.scope
};
// copy over extras
if (request.extras) {
for (let extra in request.extras) {
if (request.extras.hasOwnProperty(extra)) {
// check before inserting to requestMap
if (BUILT_IN_PARAMETERS.indexOf(extra) < 0) {
requestMap[extra] = request.extras[extra];
}
}
}
}
let query = this.utils.stringify(requestMap);
let baseUrl = configuration.authorizationEndpoint;
let url = `${baseUrl}?${query}`;
return url;
}
/**
* Completes the authorization request if necessary & when possible.
*/
completeAuthorizationRequestIfPossible(): Promise<void> {
// call complete authorization if possible to see there might
// be a response that needs to be delivered.
log(`Checking to see if there is an authorization response to be delivered.`);
if (!this.notifier) {
log(`Notifier is not present on AuthorizationRequest handler.
No delivery of result will be possible`)
}
return this.completeAuthorizationRequest().then(result => {
if (!result) {
log(`No result is available yet.`);
}
if (result && this.notifier) {
this.notifier.onAuthorizationComplete(result.request, result.response, result.error);
}
});
}
/**
* Sets the default Authorization Service notifier.
*/
setAuthorizationNotifier(notifier: AuthorizationNotifier): AuthorizationRequestHandler {
this.notifier = notifier;
return this;
};
/**
* Makes an authorization request.
*/
abstract performAuthorizationRequest(
configuration: AuthorizationServiceConfiguration,
request: AuthorizationRequest): void;
/**
* Checks if an authorization flow can be completed, and completes it.
* The handler returns a `Promise<AuthorizationRequestResponse>` if ready, or a `Promise<null>`
* if not ready.
*/
protected abstract completeAuthorizationRequest(): Promise<AuthorizationRequestResponse|null>;
}