{"version":3,"file":"providers-Dbl95AxR.mjs","names":["jose","scopes","definedScopes","serverEnv","Scope","ProviderId","Provider","id","label","clientId","clientSecret","issuer","authorizeEndpoint","tokenEndpoint","loginScopes","ReadonlyArray","audience","jwks","ReturnType","createRemoteJWKSet","logoutUrl","returnTo","entraAuthority","ENTRA_TENANT_ID","entra","ENTRA_CLIENT_ID","ENTRA_CLIENT_SECRET","URL","encodeURIComponent","awsResourceScopes","Set","Object","values","Record","map","entry","undefined","aws","filter","scope","buildAws","AWS_ISSUER","AWS_DOMAIN","AWS_CLIENT_ID","AWS_CLIENT_SECRET","providers","getProvider","provider","find","candidate","Error","getProviderByIssuer"],"sources":["../src/lib/auth/providers.ts"],"sourcesContent":["import * as jose from \"jose\";\nimport { scopes as definedScopes } from \"virtual:wcz-layout\";\nimport { serverEnv } from \"~/env\";\nimport type { Scope } from \"~/models/Scopes\";\nimport type { ProviderId } from \"~/models/User\";\n\n/**\n * Identity providers, server-side only. Entra is always present; AWS registers\n * itself when its env vars are set, so an Entra-only app is unchanged and the\n * login page renders a single button.\n */\nexport interface Provider {\n  id: ProviderId;\n  label: string;\n  clientId: string;\n  clientSecret: string;\n  /** The `iss` claim, used to pick the right provider for an incoming Bearer. */\n  issuer: string;\n  authorizeEndpoint: string;\n  tokenEndpoint: string;\n  loginScopes: ReadonlyArray<string>;\n  /**\n   * Expected `aud` for incoming Bearer JWTs. Undefined for Cognito: its access\n   * tokens carry `client_id`, not `aud`, so the user pool itself is the trust\n   * boundary — any client in the pool is accepted.\n   * ponytail: pool-wide trust; add a client_id allowlist if other pools' clients\n   * could ever reach this app.\n   */\n  audience?: string;\n  jwks: ReturnType<typeof jose.createRemoteJWKSet>;\n  logoutUrl: (returnTo: string) => string;\n}\n\nconst entraAuthority = `https://login.microsoftonline.com/${serverEnv.ENTRA_TENANT_ID}`;\n\nconst entra: Provider = {\n  id: \"entra\",\n  label: \"Microsoft\",\n  clientId: serverEnv.ENTRA_CLIENT_ID,\n  clientSecret: serverEnv.ENTRA_CLIENT_SECRET,\n  issuer: `${entraAuthority}/v2.0`,\n  authorizeEndpoint: `${entraAuthority}/oauth2/v2.0/authorize`,\n  tokenEndpoint: `${entraAuthority}/oauth2/v2.0/token`,\n  // `offline_access` yields the multi-resource refresh token every delegated API\n  // token is minted from; `User.Read` covers the Graph profile photo.\n  loginScopes: [\"openid\", \"profile\", \"offline_access\", \"User.Read\"],\n  audience: serverEnv.ENTRA_CLIENT_ID,\n  jwks: jose.createRemoteJWKSet(new URL(`${entraAuthority}/discovery/v2.0/keys`)),\n  logoutUrl: (returnTo) =>\n    `${entraAuthority}/oauth2/v2.0/logout?post_logout_redirect_uri=${encodeURIComponent(returnTo)}`,\n};\n\n/**\n * Cognito cannot widen scopes after login, so every AWS scope the app will ever\n * ask for has to be requested up front. Derived from `scopes.ts` rather than\n * configured separately, so the two can't drift.\n */\nconst awsResourceScopes = [\n  ...new Set(\n    Object.values(definedScopes as Record<string, Scope>)\n      .map((entry) => (typeof entry === \"string\" ? undefined : entry.aws))\n      .filter((scope) => scope !== undefined),\n  ),\n];\n\nconst buildAws = (): Provider | null => {\n  const { AWS_ISSUER, AWS_DOMAIN, AWS_CLIENT_ID, AWS_CLIENT_SECRET } = serverEnv;\n  if (!AWS_ISSUER || !AWS_DOMAIN || !AWS_CLIENT_ID || !AWS_CLIENT_SECRET) return null;\n\n  return {\n    id: \"aws\",\n    label: \"AWS\",\n    clientId: AWS_CLIENT_ID,\n    clientSecret: AWS_CLIENT_SECRET,\n    issuer: AWS_ISSUER,\n    authorizeEndpoint: `${AWS_DOMAIN}/oauth2/authorize`,\n    tokenEndpoint: `${AWS_DOMAIN}/oauth2/token`,\n    loginScopes: [\"openid\", \"email\", \"phone\"], // TODO: [\"openid\", \"email\", \"phone\", ...awsResourceScopes]\n    jwks: jose.createRemoteJWKSet(new URL(`${AWS_ISSUER}/.well-known/jwks.json`)),\n    logoutUrl: (returnTo) =>\n      `${AWS_DOMAIN}/logout?client_id=${AWS_CLIENT_ID}&logout_uri=${encodeURIComponent(returnTo)}`,\n  };\n};\n\nconst aws = buildAws();\n\nexport const providers: ReadonlyArray<Provider> = aws ? [entra, aws] : [entra];\n\nexport const getProvider = (id: ProviderId): Provider => {\n  const provider = providers.find((candidate) => candidate.id === id);\n  if (!provider) throw new Error(`Identity provider \"${id}\" is not configured.`);\n  return provider;\n};\n\nexport const getProviderByIssuer = (issuer: string | undefined): Provider | undefined =>\n  providers.find((candidate) => candidate.issuer === issuer);\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAiCA,MAAMsB,iBAAiB,qCAAqCnB,UAAUoB;AAEtE,MAAMC,QAAkB;CACtBjB,IAAI;CACJC,OAAO;CACPC,UAAUN,UAAUsB;CACpBf,cAAcP,UAAUuB;CACxBf,QAAQ,GAAGW,eAAc;CACzBV,mBAAmB,GAAGU,eAAc;CACpCT,eAAe,GAAGS,eAAc;CAGhCR,aAAa;EAAC;EAAU;EAAW;EAAkB;CAAW;CAChEE,UAAUb,UAAUsB;CACpBR,MAAMjB,KAAKmB,mBAAmB,IAAIQ,IAAI,GAAGL,eAAc,qBAAsB,CAAC;CAC9EF,YAAYC,aACV,GAAGC,eAAc,+CAAgDM,mBAAmBP,QAAQ;AAChG;AAO0B,CACxB,GAAG,IAAIS,IACLC,OAAOC,OAAO9B,MAAsC,CAAC,CAClDgC,KAAKC,UAAW,OAAOA,UAAU,WAAWC,KAAAA,IAAYD,MAAME,GAAI,CAAC,CACnEC,QAAQC,UAAUA,UAAUH,KAAAA,CAAS,CAC1C,CAAC;AAGH,MAAMI,iBAAkC;CACtC,MAAM,EAAEC,YAAYC,YAAYC,eAAeC,sBAAsBzC;CACrE,IAAI,CAACsC,cAAc,CAACC,cAAc,CAACC,iBAAiB,CAACC,mBAAmB,OAAO;CAE/E,OAAO;EACLrC,IAAI;EACJC,OAAO;EACPC,UAAUkC;EACVjC,cAAckC;EACdjC,QAAQ8B;EACR7B,mBAAmB,GAAG8B,WAAU;EAChC7B,eAAe,GAAG6B,WAAU;EAC5B5B,aAAa;GAAC;GAAU;GAAS;EAAO;EACxCG,MAAMjB,KAAKmB,mBAAmB,IAAIQ,IAAI,GAAGc,WAAU,uBAAwB,CAAC;EAC5ErB,YAAYC,aACV,GAAGqB,WAAU,oBAAqBC,cAAa,cAAef,mBAAmBP,QAAQ;CAC7F;AACF;AAEA,MAAMgB,MAAMG,SAAS;AAErB,MAAaK,YAAqCR,MAAM,CAACb,OAAOa,GAAG,IAAI,CAACb,KAAK;AAE7E,MAAasB,eAAevC,OAA6B;CACvD,MAAMwC,WAAWF,UAAUG,MAAMC,cAAcA,UAAU1C,OAAOA,EAAE;CAClE,IAAI,CAACwC,UAAU,MAAM,IAAIG,MAAM,sBAAsB3C,GAAE,qBAAsB;CAC7E,OAAOwC;AACT;AAEA,MAAaI,uBAAuBxC,WAClCkC,UAAUG,MAAMC,cAAcA,UAAUtC,WAAWA,MAAM"}