text: !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define("authentication-backend",[],t):"object"==typeof exports?exports["authentication-backend"]=t():e["authentication-backend"]=t()}(global,(function(){return function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=5)}([function(e,t){e.exports=require("node-fetch")},function(e,t){e.exports=require("express")},function(e,t){e.exports=require("jwt-simple")},function(e,t){e.exports=require("crypto")},function(e,t){e.exports=require("uuid")},function(e,t,n){e.exports=n(6)},function(e,t,n){"use strict";n.r(t),n.d(t,"AuthenticationService",(function(){return u})),n.d(t,"buildAuthenticationRouter",(function(){return f})),n.d(t,"buildMockSsoApp",(function(){return w})),n.d(t,"buildAuthenticationBackend",(function(){return v}));var r=n(0),o=n.n(r);async function i(e,t){const n=new URLSearchParams;n.append("id_token",t);const r=await o()(`${e.tokenInfoUrl}?${n.toString()}`);if(r.status>=500)throw new Error("validation internal error");const i=await r.json();if(200!==r.status||i.error)throw new Error("validation error: "+i.error);if(i.aud!==e.clientId)throw new Error("audience mismatch");return i.sub}async function a(e,t){const n=new URLSearchParams;n.append("code",t),n.append("client_id",e.clientId),n.append("client_secret",e.clientSecret);const r=await o()(e.accessTokenUrl,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:n.toString()}),i=new URLSearchParams(await r.text()),a=i.get("error");if(a)throw new Error("validation error: "+a);const c=i.get("access_token");if(!c)throw new Error("validation internal error");const s=await o()(e.userUrl,{headers:{Authorization:"Bearer "+c}});return(await s.json()).id}async function c(e,t){const n=await o()(e.tokenInfoUrl,{method:"GET",headers:{Authorization:"Bearer "+t}});if(n.status>=500)throw new Error("validation internal error");const r=await n.json();if(200!==n.status||r.error)throw new Error("validation error: "+r.error);if(r.application.uid!==e.clientId)throw new Error("audience mismatch");return r.resource_owner_id}function s(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}class u{constructor(e){s(this,"clientConfig",{}),s(this,"extractors",new Map),this.bindExtractor(e,"google",i),this.bindExtractor(e,"github",a),this.bindExtractor(e,"gitlab",c)}supportsService(e){return this.extractors.has(e)}extractId(e,t){const n=this.extractors.get(e);if(!n)throw new Error(`Login integration with ${e} is not supported`);return n(t)}bindExtractor(e,t,n){const r=e[t];null!=r&&r.clientId&&(this.extractors.set(t,n.bind(null,r)),this.clientConfig[t]={authUrl:r.authUrl,clientId:r.clientId})}}var d=n(1),l=n.n(d);const p=l.a.json({limit:4096});function f(e,t){const n=l.a.Router();return n.get("/",(t,n)=>{n.status(200).json(e.clientConfig)}),n.post("/:name",p,async(n,r,o)=>{const{name:i}=n.params;if(!e.supportsService(i))return void o();const{externalToken:a}=n.body;if(a&&"string"==typeof a)try{const n=await e.extractId(i,a);if(!n)throw new Error("failed to get user ID");const o=t(`${i}-${n}`,i,n);r.status(200).json({userToken:o})}catch(e){e instanceof Error&&"validation internal error"!==e.message?r.status(400).json({error:e.message||"unknown error"}):r.status(500).json({error:"internal error"})}else r.status(400).json({error:"no externalToken provided"})}),n}var h=n(3),g=n.n(h),m=n(2),b=n.n(m),y=n(4);function x(e){return e&&"string"==typeof e?e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#039;"):""}var w=()=>{const e=g.a.generateKeyPairSync("rsa",{modulusLength:2048,privateKeyEncoding:{type:"pkcs8",format:"pem"},publicKeyEncoding:{type:"spki",format:"pem"}}),t=l()();return t.get("/auth",(e,t)=>{var n;t.header("Content-Type","text/html").send(`\n<html>\n  <head>\n    <title>Mock OAuth service</title>\n    <style>\n      body {\n        background: #EEEEEE;\n        font: 1em sans-serif;\n        margin: 0;\n        padding: 0;\n      }\n      form {\n        width: 400px;\n        max-width: calc(100% - 20px);\n        box-sizing: border-box;\n        margin: 50px auto;\n        padding: 15px;\n        background: #FFFFFF;\n      }\n      h1 {\n        margin: 0 0 20px;\n        text-align: center;\n      }\n      p {\n        font-size: 0.8em;\n        margin: 20px 0;\n      }\n      input[type=text] {\n        width: 200px;\n        font-size: 0.9em;\n        padding: 4px;\n        margin: 0 10px;\n      }\n      button {\n        font-size: 0.9em;\n        padding: 6px 12px;\n        border: none;\n        background: #008800;\n        color: #FFFFFF;\n        cursor: pointer;\n      }\n    </style>\n  </head>\n  <body>\n    <form method="POST">\n      <h1>Mock OAuth service</h1>\n      <p>\n        This is a mock implementation of an OAuth server for testing purposes.\n      </p>\n      <input type="hidden" name="redirect_uri" value="${x((n=e.query).redirect_uri)}" />\n      <input type="hidden" name="nonce" value="${x(n.nonce)}" />\n      <input type="hidden" name="state" value="${x(n.state)}" />\n      <input type="hidden" name="client_id" value="${x(n.client_id)}" />\n      <label>Sign in as <input type="text" name="identifier" required autofocus /></label><button>Sign in</button>\n    </form>\n  </body>\n</html>\n`)}),t.post("/auth",l.a.urlencoded({extended:!1}),(t,n)=>{const{redirect_uri:r,nonce:o,state:i,client_id:a,identifier:c}=t.body;r&&a&&c||n.status(400).json({error:"missing fields"});const s=Math.floor(Date.now()/1e3),u=b.a.encode({aud:a,nonce:o,jti:Object(y.v4)(),sub:c,iat:s,exp:s+3600},e.privateKey,"RS256"),d=new URLSearchParams;d.set("id_token",u),d.set("state",i),n.redirect(303,`${r}#${d.toString()}`)}),t.get("/tokeninfo",(t,n)=>{const{id_token:r}=t.query;try{if("string"!=typeof r)throw new Error("Expected string id_token");n.json(b.a.decode(r,e.publicKey,!1,"RS256"))}catch(e){n.status(400).json({error:"validation failure"})}}),t};function v(e,t){const n=new u(e);return{router:f(n,t),service:n}}}])}));
  //# sourceMappingURL=index.js.map