// eslint-disable-next-line @typescript-eslint/ban-ts-comment
import { AccessToken } from './AccessToken.js';
import { withHeaders } from './auth.js';
/**
 * Class that provides OIDC functionality to auth providers.
 *
 * Note that this class itself is not a provider - providers implement
 * `AuthProvider` and make use of this class.
 *
 * Both browser and non-browser flows use OIDC, but the supported OIDC auth
 * mechanisms differ between  public (e.g. browser) clients, and confidential
 * (e.g. Node) clients.
 *
 * The non-browser flow just expects a `clientId` and `clientSecret` to be
 * provided in the `clientConfig`, and will use that
 * to grant tokens via the OIDC `clientCredentials` flow.
 *
 * For either kind of client, the client's public key must be set in all OIDC
 * token requests in order to recieve a token with valid TDF claims. The public
 * key may be passed to this provider's constructor, or supplied
 * post-construction by calling @see updateClientPublicKey, which forces an
 * explicit token refresh
 */
export default class VirtruOIDC {
    /**
     * If clientId and clientSecret are provided, clientCredentials mode will be assumed.
     *
     * If clientId and clientSecret are not provided, browser mode will be assumed, and @see refreshTokenWithVirtruClaims must be
     * manually called during object initialization to do a token exchange.
     */
    constructor({ clientId, clientSecret, oidcOrigin }) {
        if (!clientId) {
            throw new Error('To use any OIDC auth mode you must supply your clientId, at a minimum');
        }
        let keycloakConfig = {
            client_id: clientId,
            auth_server_url: oidcOrigin,
        };
        //If we have a client secret, we must be using client credentials, and this is not
        // a public client (aka this is not a browser context)
        if (clientSecret) {
            keycloakConfig = {
                client_secret: clientSecret,
                auth_mode: 'credentials',
                ...keycloakConfig,
            };
        }
        else {
            //This is a browser client which is exchanging a Keycloak IdP-issued refresh token
            keycloakConfig = {
                auth_mode: 'browser',
                ...keycloakConfig,
            };
        }
        this.accessTokenGetter = new AccessToken(keycloakConfig);
    }
    /**
     * This function should be called if the consumer of this auth provider changes the client keypair,
     * or wishes to set the keypair after creating the object.
     *
     * Calling this function will trigger a forcible token refresh using the cached refresh token, and contact the auth server.
     */
    async refreshTokenClaimsWithClientPubkeyIfNeeded(clientPubKey, signingKey) {
        // If we already have a token, and the pubkey changes,
        // we need to force a refresh now - otherwise
        // we can wait until we create the token for the first time
        if (this.currentAccessToken && clientPubKey === this.accessTokenGetter.virtru_client_pubkey) {
            return;
        }
        this.accessTokenGetter.virtru_client_pubkey = clientPubKey;
        this.accessTokenGetter.signing_key = signingKey;
    }
    async getCurrentAccessToken() {
        if (!this.accessTokenGetter.virtru_client_pubkey && !this.accessTokenGetter.signing_key) {
            throw new Error('Client public key was not set via `updateClientPublicKey` or passed in via constructor, cannot fetch OIDC token with valid Virtru claims');
        }
        if (!this.currentAccessToken) {
            this.currentAccessToken = await this.accessTokenGetter.get();
        }
        return this.currentAccessToken;
    }
    /**
     * This function checks to see if we need to perform the one-time operation of exchanging a valid OIDC token
     * that lacks Virtru claims (because it hasn't been associated with a client pubkey yet) for
     *
     */
    async exchangeExternalRefreshToken(externalRefreshToken) {
        if (!externalRefreshToken) {
            throw new Error('No external refresh token provided!');
        }
        //Do a token exchange now, taking the provided refresh token and requesting a new access token
        // from Keycloak with updated Virtru claims
        this.currentAccessToken = await this.accessTokenGetter.refresh(externalRefreshToken);
        return this.currentAccessToken;
    }
    /**
     * This function checks to see if we need to perform the one-time operation of exchanging a valid OIDC token
     * that lacks Virtru claims (because it hasn't been associated with a client pubkey yet) for
     *
     */
    async exchangeExternalJwt(externalJwt) {
        if (!externalJwt) {
            throw new Error('No external JWT provided!');
        }
        //Do a token exchange taking the provided exernal 3rd-party token and requesting a new access token
        // from Keycloak with updated Virtru claims
        const cat = await this.accessTokenGetter.exchangeJwt(externalJwt);
        this.currentAccessToken = cat;
        return cat;
    }
    async withCreds(httpReq) {
        const accessToken = await this.getCurrentAccessToken();
        if (this.accessTokenGetter.signing_key) {
            const { default: dpopFn } = await import('dpop');
            const dpopToken = await dpopFn(this.accessTokenGetter.signing_key, httpReq.url, httpReq.method, 
            /* nonce */ undefined, accessToken);
            // TODO: Consider: only set DPoP if cnf.jkt is present in access token?
            return withHeaders(httpReq, { Authorization: `Bearer ${accessToken}`, DPoP: dpopToken });
        }
        return withHeaders(httpReq, { Authorization: `Bearer ${accessToken}` });
    }
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmlydHJ1LW9pZGMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvYXV0aC92aXJ0cnUtb2lkYy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSw2REFBNkQ7QUFDN0QsT0FBTyxFQUFFLFdBQVcsRUFBcUIsTUFBTSxlQUFlLENBQUM7QUFFL0QsT0FBTyxFQUFlLFdBQVcsRUFBRSxNQUFNLFFBQVEsQ0FBQztBQUVsRDs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQW1CRztBQUNILE1BQU0sQ0FBQyxPQUFPLE9BQU8sVUFBVTtJQUk3Qjs7Ozs7T0FLRztJQUNILFlBQVksRUFBRSxRQUFRLEVBQUUsWUFBWSxFQUFFLFVBQVUsRUFBZTtRQUM3RCxJQUFJLENBQUMsUUFBUSxFQUFFO1lBQ2IsTUFBTSxJQUFJLEtBQUssQ0FBQyx1RUFBdUUsQ0FBQyxDQUFDO1NBQzFGO1FBQ0QsSUFBSSxjQUFjLEdBQXNCO1lBQ3RDLFNBQVMsRUFBRSxRQUFRO1lBQ25CLGVBQWUsRUFBRSxVQUFVO1NBQzVCLENBQUM7UUFFRixrRkFBa0Y7UUFDbEYsc0RBQXNEO1FBQ3RELElBQUksWUFBWSxFQUFFO1lBQ2hCLGNBQWMsR0FBRztnQkFDZixhQUFhLEVBQUUsWUFBWTtnQkFDM0IsU0FBUyxFQUFFLGFBQWE7Z0JBQ3hCLEdBQUcsY0FBYzthQUNsQixDQUFDO1NBQ0g7YUFBTTtZQUNMLGtGQUFrRjtZQUNsRixjQUFjLEdBQUc7Z0JBQ2YsU0FBUyxFQUFFLFNBQVM7Z0JBQ3BCLEdBQUcsY0FBYzthQUNsQixDQUFDO1NBQ0g7UUFDRCxJQUFJLENBQUMsaUJBQWlCLEdBQUcsSUFBSSxXQUFXLENBQUMsY0FBYyxDQUFDLENBQUM7SUFDM0QsQ0FBQztJQUVEOzs7OztPQUtHO0lBQ0gsS0FBSyxDQUFDLDBDQUEwQyxDQUM5QyxZQUFvQixFQUNwQixVQUEwQjtRQUUxQixzREFBc0Q7UUFDdEQsNkNBQTZDO1FBQzdDLDJEQUEyRDtRQUMzRCxJQUFJLElBQUksQ0FB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