'use strict';

var errors = require('@backstage/errors');
var jose = require('jose');
var getBearerTokenFromAuthorizationHeader = require('./getBearerTokenFromAuthorizationHeader.cjs.js');

const CLOCK_MARGIN_S = 10;
class DefaultIdentityClient {
  discovery;
  issuer;
  algorithms;
  keyStore;
  keyStoreUpdated = 0;
  /**
   * Create a new {@link DefaultIdentityClient} instance.
   */
  static create(options) {
    return new DefaultIdentityClient(options);
  }
  constructor(options) {
    this.discovery = options.discovery;
    this.issuer = options.issuer;
    this.algorithms = options.hasOwnProperty("algorithms") ? options.algorithms : ["ES256"];
  }
  async getIdentity(options) {
    const {
      request: { headers }
    } = options;
    if (!headers.authorization) {
      return void 0;
    }
    try {
      return await this.authenticate(
        getBearerTokenFromAuthorizationHeader.getBearerTokenFromAuthorizationHeader(headers.authorization)
      );
    } catch (e) {
      throw new errors.AuthenticationError(e.message);
    }
  }
  /**
   * Verifies the given backstage identity token
   * Returns a BackstageIdentity (user) matching the token.
   * The method throws an error if verification fails.
   *
   * @deprecated You should start to use getIdentity instead of authenticate to retrieve the user
   * identity.
   */
  async authenticate(token) {
    if (!token) {
      throw new errors.AuthenticationError("No token specified");
    }
    await this.refreshKeyStore(token);
    if (!this.keyStore) {
      throw new errors.AuthenticationError("No keystore exists");
    }
    const decoded = await jose.jwtVerify(token, this.keyStore, {
      algorithms: this.algorithms,
      audience: "backstage",
      issuer: this.issuer
    });
    if (!decoded.payload.sub) {
      throw new errors.AuthenticationError("No user sub found in token");
    }
    const user = {
      token,
      identity: {
        type: "user",
        userEntityRef: decoded.payload.sub,
        ownershipEntityRefs: decoded.payload.ent ? decoded.payload.ent : []
      }
    };
    return user;
  }
  /**
   * If the last keystore refresh is stale, update the keystore URL to the latest
   */
  async refreshKeyStore(rawJwtToken) {
    const payload = await jose.decodeJwt(rawJwtToken);
    const header = await jose.decodeProtectedHeader(rawJwtToken);
    let keyStoreHasKey;
    try {
      if (this.keyStore) {
        const [_, rawPayload, rawSignature] = rawJwtToken.split(".");
        keyStoreHasKey = await this.keyStore(header, {
          payload: rawPayload,
          signature: rawSignature
        });
      }
    } catch (error) {
      keyStoreHasKey = false;
    }
    const issuedAfterLastRefresh = payload?.iat && payload.iat > this.keyStoreUpdated - CLOCK_MARGIN_S;
    if (!this.keyStore || !keyStoreHasKey && issuedAfterLastRefresh) {
      const url = await this.discovery.getBaseUrl("auth");
      const endpoint = new URL(`${url}/.well-known/jwks.json`);
      this.keyStore = jose.createRemoteJWKSet(endpoint);
      this.keyStoreUpdated = Date.now() / 1e3;
    }
  }
}

exports.DefaultIdentityClient = DefaultIdentityClient;
//# sourceMappingURL=DefaultIdentityClient.cjs.js.map
