piral-oauth2
Version:
Plugin to integrate OAuth 2.0 authentication in Piral.
2 lines (1 loc) • 10.9 kB
JavaScript
var piralOAuth2=(()=>{var j=Object.defineProperty;var Q=Object.getOwnPropertyDescriptor;var G=Object.getOwnPropertyNames;var V=Object.prototype.hasOwnProperty;var W=(t,e)=>{for(var n in e)j(t,n,{get:e[n],enumerable:!0})},X=(t,e,n,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of G(e))!V.call(t,r)&&r!==n&&j(t,r,{get:()=>e[r],enumerable:!(i=Q(e,r))||i.enumerable});return t};var Y=t=>X(j({},"__esModule",{value:!0}),t);var se={};W(se,{createOAuth2Api:()=>Z,createOAuth2BrowserPersistence:()=>ne,createOAuth2MemoryPersistence:()=>L,createOAuth2SessionPersistence:()=>re,setupOAuth2Client:()=>ie});function Z(t){return e=>(e.on("before-fetch",t.extendHeaders),{getAccessToken(){return t.token()}})}var k=location.origin;function K(t,e,n,i){return fetch(e,{body:n,method:t,headers:i}).then(r=>r.text().then(s=>({status:r.status,body:s})))}var g={Accept:"application/json, application/x-www-form-urlencoded","Content-Type":"application/x-www-form-urlencoded"},ee={invalid_request:["The request is missing a required parameter, includes an","invalid parameter value, includes a parameter more than","once, or is otherwise malformed."].join(" "),invalid_client:["Client authentication failed (e.g., unknown client, no","client authentication included, or unsupported","authentication method)."].join(" "),invalid_grant:["The provided authorization grant (e.g., authorization","code, resource owner credentials) or refresh token is","invalid, expired, revoked, does not match the redirection","URI used in the authorization request, or was issued to","another client."].join(" "),unauthorized_client:["The client is not authorized to request an authorization","code using this method."].join(" "),unsupported_grant_type:["The authorization grant type is not supported by the","authorization server."].join(" "),access_denied:["The resource owner or authorization server denied the request."].join(" "),unsupported_response_type:["The authorization server does not support obtaining","an authorization code using this method."].join(" "),invalid_scope:["The requested scope is invalid, unknown, or malformed."].join(" "),server_error:["The authorization server encountered an unexpected","condition that prevented it from fulfilling the request.","(This error code is needed because a 500 Internal Server","Error HTTP status code cannot be returned to the client","via an HTTP redirect.)"].join(" "),temporarily_unavailable:["The authorization server is currently unable to handle","the request due to a temporary overloading or maintenance","of the server."].join(" ")};function b(t,...e){for(let i=0;i<e.length;i++){var n=e[i];if(t[n]==null)throw new TypeError('Expected "'+n+'" to exist')}}function I(t){var e=ee[t.error]||t.error_description||t.error;if(e){let n=new Error(e);return n.body=t,n.code="EAUTH",n}}function w(t){let e=new URLSearchParams(t);return Object.fromEntries(e.entries())}function U(t){return new URLSearchParams(t).toString()}function te(t){try{return JSON.parse(t)}catch{return w(t)}}function O(t){return Array.isArray(t)?t.join(" "):S(t)}function F(t,e){b(t,"clientId","authorizationUri");let n={client_id:t.clientId,redirect_uri:t.redirectUri,response_type:e,state:t.state};t.scopes!==void 0&&(n.scope=O(t.scopes));let i=t.authorizationUri.includes("?")?"&":"?";return t.authorizationUri+i+U(Object.assign(n,t.query))}function f(t,e){return"Basic "+btoa(S(t)+":"+S(e))}function S(t){return t==null?"":String(t)}function p(t,e){return{url:t.url,method:t.method,body:Object.assign({},t.body,e.body),query:Object.assign({},t.query,e.query),headers:Object.assign({},t.headers,e.headers)}}var v=class{constructor(e,n=K){this.options=e;this.request=n;this.code=new z(this),this.token=new C(this),this.owner=new R(this),this.credentials=new E(this),this.jwt=new q(this)}createToken(e,n,i,r){var s=Object.assign({},r,typeof e=="string"?{access_token:e}:e,typeof n=="string"?{refresh_token:n}:n,typeof i=="string"?{token_type:i}:i);return new x(this,s)}_request(e){let n=e.url,i=U(e.body),r=U(e.query);return r&&(n+=(n.indexOf("?")===-1?"?":"&")+r),this.request(e.method,n,i,e.headers).then(s=>{let o=te(s.body),a=I(o);if(a)return Promise.reject(a);if(s.status<200||s.status>=399){let d=new Error("HTTP status "+s.status);return d.status=s.status,d.body=s.body,d.code="ESTATUS",Promise.reject(d)}return o})}},x=class{constructor(e,n){this.client=e,this.data=n,this.tokenType=n.token_type&&n.token_type.toLowerCase(),this.accessToken=n.access_token,this.refreshToken=n.refresh_token,this.expiresIn(Number(n.expires_in))}expiresIn(e){if(typeof e=="number")this.expires=new Date,this.expires.setSeconds(this.expires.getSeconds()+e);else if(e instanceof Date)this.expires=new Date(e.getTime());else throw new TypeError("Unknown duration: "+e);return this.expires}sign(e){if(!this.accessToken)throw new Error("Unable to sign without access token");if(e.headers=e.headers||{},this.tokenType==="bearer")e.headers.Authorization="Bearer "+this.accessToken;else{var n=e.url.split("#"),i="access_token="+this.accessToken,r=n[0].replace(/[?&]access_token=[^&#]/,""),s=n[1]?"#"+n[1]:"";e.url=r+(r.indexOf("?")>-1?"&":"?")+i+s,e.headers.Pragma="no-store",e.headers["Cache-Control"]="no-store"}return e}refresh(e){var n=this,i=Object.assign({},this.client.options,e);return this.refreshToken?this.client._request(p({url:i.accessTokenUri,method:"POST",headers:Object.assign({},g,{Authorization:f(i.clientId,i.clientSecret)}),body:{refresh_token:this.refreshToken,grant_type:"refresh_token"}},i)).then(r=>n.client.createToken(void 0,void 0,void 0,Object.assign({},n.data,r))):Promise.reject(new Error("No refresh token"))}expired(){return Date.now()>this.expires.getTime()}},R=class{constructor(e){this.client=e}getToken(e,n,i){var r=this,s=Object.assign({},this.client.options,i);let o={username:e,password:n,grant_type:"password"};return s.scopes!==void 0&&(o.scope=O(s.scopes)),this.client._request(p({url:s.accessTokenUri,method:"POST",headers:Object.assign({},g,{Authorization:f(s.clientId,s.clientSecret)}),body:o},s)).then(a=>r.client.createToken(void 0,void 0,void 0,a))}},C=class{constructor(e){this.client=e}getUri(e){var n=Object.assign({},this.client.options,e);return F(n,"token")}getToken(e,n){var i=Object.assign({},this.client.options,n),r=typeof e=="object"?e:new URL(e,k),s=new URL(i.redirectUri,k);if(typeof r.pathname=="string"&&r.pathname!==s.pathname)return Promise.reject(new TypeError("Redirected path should match configured path, but got: "+r.pathname));if(!r.hash&&!r.search)return Promise.reject(new TypeError("Unable to process uri: "+e));var o=Object.assign({},typeof r.search=="string"?w(r.search.substr(1)):r.search||{},typeof r.hash=="string"?w(r.hash.substr(1)):r.hash||{}),a=I(o);return a?Promise.reject(a):i.state!=null&&o.state!==i.state?Promise.reject(new TypeError("Invalid state: "+o.state)):Promise.resolve(this.client.createToken(void 0,void 0,void 0,o))}},E=class{constructor(e){this.client=e}getToken(e){var n=this,i=Object.assign({},this.client.options,e);b(i,"clientId","clientSecret","accessTokenUri");let r={grant_type:"client_credentials"};return i.scopes!==void 0&&(r.scope=O(i.scopes)),this.client._request(p({url:i.accessTokenUri,method:"POST",headers:Object.assign({},g,{Authorization:f(i.clientId,i.clientSecret)}),body:r},i)).then(s=>n.client.createToken(void 0,void 0,void 0,s))}},z=class{constructor(e){this.client=e}getUri(e){var n=Object.assign({},this.client.options,e);return F(n,"code")}getToken(e,n){var i=this,r=Object.assign({},this.client.options,n);b(r,"clientId","accessTokenUri");var s=typeof e=="object"?e:new URL(e,k);if(typeof r.redirectUri=="string"&&typeof s.pathname=="string"&&s.pathname!==new URL(r.redirectUri,k).pathname)return Promise.reject(new TypeError("Redirected path should match configured path, but got: "+s.pathname));if(!s.search||!s.search.substr(1))return Promise.reject(new TypeError("Unable to process uri: "+e));var o=typeof s.search=="string"?w(s.search.substr(1)):s.search||{},a=I(o);if(a)return Promise.reject(a);if(r.state!=null&&o.state!==r.state)return Promise.reject(new TypeError("Invalid state: "+o.state));if(!o.code)return Promise.reject(new TypeError("Missing code, unable to request token"));let d=Object.assign({},g),y={code:o.code,grant_type:"authorization_code",redirect_uri:r.redirectUri};return r.clientSecret?d.Authorization=f(r.clientId,r.clientSecret):y.client_id=r.clientId,this.client._request(p({url:r.accessTokenUri,method:"POST",headers:d,body:y},r)).then(A=>i.client.createToken(void 0,void 0,void 0,A))}},q=class{constructor(e){this.client=e}getToken(e,n){let i=this,r=Object.assign({},this.client.options,n),s=Object.assign({},g);b(r,"accessTokenUri"),r.clientId&&(s.Authorization=f(r.clientId,r.clientSecret));let o={grant_type:"urn:ietf:params:oauth:grant-type:jwt-bearer",assertion:e};return r.scopes!==void 0&&(o.scope=O(r.scopes)),this.client._request(p({url:r.accessTokenUri,method:"POST",headers:s,body:o},r)).then(a=>i.client.createToken(void 0,void 0,void 0,a))}};function L(){return{load(){},save(){}}}function re(t="$piral_oauth2_info"){return{load(){let e=sessionStorage.getItem(t);if(typeof e=="string")try{return JSON.parse(e)}catch{console.error("Found invalid data in the OAuth 2 session storage key. Skipped.")}},save(e){sessionStorage.setItem(t,JSON.stringify(e))}}}function ne(t="$piral_oauth2_info"){return{load(){let e=localStorage.getItem(t);if(typeof e=="string")try{return JSON.parse(e)}catch{console.error("Found invalid data in the OAuth 2 local storage key. Skipped.")}},save(e){localStorage.setItem(t,JSON.stringify(e))}}}var N="oauth2Cb";function ie(t){let{clientId:e,clientSecret:n,authorizationUri:i,accessTokenUri:r,redirectUri:s=`${location.origin}/auth`,scopes:o=[],flow:a,headers:d,query:y,state:A,restrict:$=!1,returnPath:M="/",persist:D=L()}=t,l=new v({clientId:e,clientSecret:n,redirectUri:s,authorizationUri:i,accessTokenUri:r,scopes:o,headers:d,query:y,state:A}),h,m,_,H=c=>{D.save({accessToken:c.accessToken,data:c.data,refreshToken:c.refreshToken}),h=c},B=(c,u)=>c.then(()=>h?h.expired()?u().then(T=>(H(T),h.accessToken)):h.accessToken:Promise.reject("Not logged in. Please call `login()` to retrieve a token.")),J=c=>{let u=D.load();return u?(h=l.createToken(u.accessToken,u.refreshToken,void 0,u.data),Promise.resolve()):c().then(T=>{let P=window.opener;H(T),P&&typeof P[N]=="function"&&(P[N](T),window.close())},()=>{})};if(a==="code"){let c=J(()=>{let u=location.href;return history.replaceState(void 0,void 0,M),l.code.getToken(u)});m=()=>B(c,()=>h.refresh()),_=()=>l.code.getUri()}else{let c=J(()=>l.token.getToken(location.href));m=()=>B(c,()=>new Promise(u=>{window[N]=u,window.open(l.token.getUri())})),_=()=>l.token.getUri()}return{_:l,login(){window.location.href=_()},logout(){h=void 0},extendHeaders(c){$||c.setHeaders(m().then(u=>u&&{Authorization:`Bearer ${u}`},()=>{}))},account(){return!!h},token:m}}return Y(se);})();