var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    return function (d, b) {
        if (typeof b !== "function" && b !== null)
            throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var __assign = (this && this.__assign) || function () {
    __assign = Object.assign || function(t) {
        for (var s, i = 1, n = arguments.length; i < n; i++) {
            s = arguments[i];
            for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
                t[p] = s[p];
        }
        return t;
    };
    return __assign.apply(this, arguments);
};
/**
 * Module dependencies.
 */
var uid = require("uid2");
var querystring = require("querystring");
var OAuth2Strategy = require("passport-oauth2");
var InternalOAuthError = require("passport-oauth2").InternalOAuthError;
/**
 * @typedef {Object} UniqueOktaStrategyOptions
 * @property {string} audience audience is the Okta Domain, e.g. `https://example.okta.com`,
 * `https://example.oktapreview.com`
 * @property {string | undefined} authServerID authServerID is the authorization server ID. If it is defined, the token
 * URL might be something like `https://example.okta.com/oauth2/authServerID/v1/token`
 * @property {string | undefined} idp idp is the Identity Provider (id). This is an optional field. it's a 20 character
 * alphanumeric string, e.g. `qOp8aaJmCEhvep5Il6ZJ`  (generated example)
 * @property {boolean | undefined} passReqToCallback With this option enabled, `req` will be passed as the first argument to the
 * verify callback.
 * @property {'code'} response_type Set this to 'code'
 */
/**
 * @typedef {UniqueOktaStrategyOptions & Omit<import("passport-oauth2")._StrategyOptionsBase, "authorizationURL" | "tokenURL">} OktaStrategyOptions
 */
/**
 * @extends OAuth2Strategy
 */
var Strategy = /** @class */ (function (_super) {
    __extends(Strategy, _super);
    /**
     * @param {OktaStrategyOptions | undefined} options
     * @param {import("passport-oauth2").VerifyFunction | import("passport-oauth2").VerifyFunctionWithRequest} verify
     */
    function Strategy(options, verify) {
        var _this = this;
        var baseUrl = options.authServerID
            ? "".concat(options.audience, "/oauth2/").concat(options.authServerID, "/v1")
            : "".concat(options.audience, "/oauth2/v1");
        var configuredOptions = __assign(__assign({}, options), { authorizationURL: "".concat(baseUrl, "/authorize"), tokenURL: "".concat(baseUrl, "/token"), userInfoUrl: "".concat(baseUrl, "/userinfo") });
        _this = _super.call(this, configuredOptions, verify) || this;
        _this.name = "okta";
        _this._userInfoUrl = configuredOptions.userInfoUrl;
        _this._idp = configuredOptions.idp;
        _this._state = configuredOptions.state;
        // Authorize Request using Authorization Header
        _this._oauth2.getOAuthAccessToken = function (code, params, callback) {
            params = params || {};
            var codeParam = params.grant_type === "refresh_token" ? "refresh_token" : "code";
            params[codeParam] = code;
            var post_data = querystring.stringify(params);
            var post_headers = {
                "Content-Type": "application/x-www-form-urlencoded",
                Authorization: "Basic: " +
                    new Buffer(this._clientId + ":" + this._clientSecret).toString("base64")
            };
            this._request("POST", this._getAccessTokenUrl(), post_headers, post_data, null, function (error, data) {
                if (error)
                    callback(error);
                else {
                    var results = void 0;
                    try {
                        // As of http://tools.ietf.org/html/draft-ietf-oauth-v2-07
                        // responses should be in JSON
                        results = JSON.parse(data);
                    }
                    catch (e) {
                        // .... However both Facebook + Github currently use rev05 of the spec
                        // and neither seem to specify a content-type correctly in their response headers :(
                        // clients of these services will suffer a *minor* performance cost of the exception
                        // being thrown
                        results = querystring.parse(data);
                    }
                    var access_token = results["access_token"];
                    var refresh_token = results["refresh_token"];
                    delete results["refresh_token"];
                    callback(null, access_token, refresh_token, results); // callback results =-=
                }
            });
        };
        return _this;
    }
    /**
     * Retrieve user profile from Okta.
     * Further references at http://developer.okta.com/docs/api/resources/oidc.html#get-user-information
     *
     * This function constructs a normalized profile, with the following properties:
     *
     *   - `provider`         always set to `okta`
     *   - `id`
     *   - `username`
     *   - `displayName`
     *
     * @param {String} accessToken
     * @param {Function} done
     * @api protected
     */
    Strategy.prototype.userProfile = function (accessToken, done) {
        var post_headers = { Authorization: "Bearer " + accessToken };
        // noinspection JSAccessibilityCheck
        this._oauth2._request("POST", this._userInfoUrl, post_headers, "", null, function (err, body) {
            if (err) {
                return done(new InternalOAuthError("failed to fetch user profile", err));
            }
            try {
                var json = JSON.parse(body);
                done(null, {
                    provider: "tsokta",
                    id: json.sub,
                    displayName: json.name,
                    username: json.preferred_username,
                    name: {
                        fullName: json.name,
                        familyName: json.family_name,
                        givenName: json.given_name
                    },
                    emails: [{ value: json.email }],
                    _raw: body,
                    _json: json
                });
            }
            catch (e) {
                done(e);
            }
        });
    };
    /**
     * Return extra Okta-specific parameters to be included in the authorization
     * request.
     *
     * @param {Object} option
     * @return {Object}
     * @api protected
     */
    Strategy.prototype.authorizationParams = function (option) {
        var params = {};
        if (this._state) {
            params.state = true;
            params.nonce = uid(24);
        }
        if (this._idp) {
            params.idp = this._idp;
        }
        return params;
    };
    return Strategy;
}(OAuth2Strategy));
/**
 * Expose `Strategy`.
 */
module.exports = Strategy;
