@alien_org/sso-sdk-core 1.0.19 → 1.0.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";var d=(h,e,o)=>new Promise((r,s)=>{var a=l=>{try{c(o.next(l))}catch(m){s(m)}},n=l=>{try{c(o.throw(l))}catch(m){s(m)}},c=l=>l.done?r(l.value):Promise.resolve(l.value).then(a,n);c((o=o.apply(h,e)).next())});Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("zod/v4-mini"),b=require("js-sha256"),k=t.z.object({deep_link:t.z.string(),polling_code:t.z.string(),expired_at:t.z.number()}),w=t.z.object({polling_code:t.z.string()}),R=["pending","authorized","rejected","expired"],I=t.z.enum(R),y=t.z.object({status:I,authorization_code:t.z.optional(t.z.string())}),f=t.z.object({access_token:t.z.string(),token_type:t.z.string(),expires_in:t.z.number(),id_token:t.z.string(),refresh_token:t.z.string()}),z=t.z.object({sub:t.z.string()}),T=t.z.object({iss:t.z.string(),sub:t.z.string(),aud:t.z.union([t.z.string(),t.z.array(t.z.string())]),exp:t.z.number(),iat:t.z.number(),nonce:t.z.optional(t.z.string()),auth_time:t.z.optional(t.z.number())}),j=f;function S(h){return btoa(h).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}function _(h){let e=h.replace(/-/g,"+").replace(/_/g,"/");for(;e.length%4;)e+="=";return atob(e)}const x="https://sso.alien.com",E=5e3,i="alien-sso_",u=i+"refresh_token",g=i+"token_expiry",p=(h,e)=>new URL(e,h).toString(),A=t.z.object({ssoBaseUrl:t.z.url(),providerAddress:t.z.string(),pollingInterval:t.z.optional(t.z.number())});class v{constructor(e){this.config=A.parse(e),this.ssoBaseUrl=this.config.ssoBaseUrl||x,this.providerAddress=this.config.providerAddress,this.pollingInterval=this.config.pollingInterval||E}generateCodeVerifier(e=128){let o;const r=typeof window!="undefined"&&window.crypto;if(r&&r.getRandomValues)o=new Uint8Array(e),r.getRandomValues(o);else{o=new Uint8Array(e);for(let a=0;a<e;a++)o[a]=Math.floor(Math.random()*256)}let s="";for(let a=0;a<o.length;a++)s+=String.fromCharCode(o[a]);return S(s)}generateCodeChallenge(e){const o=b.sha256.array(e),r=String.fromCharCode(...o);return S(r)}generateDeeplink(){return d(this,null,function*(){const e=this.generateCodeVerifier(),o=this.generateCodeChallenge(e);sessionStorage.setItem(i+"code_verifier",e);const r=new URLSearchParams({response_type:"code",response_mode:"json",client_id:this.providerAddress,scope:"openid",code_challenge:o,code_challenge_method:"S256"}),s=`${this.config.ssoBaseUrl}/oauth/authorize?${r.toString()}`,a=yield fetch(s,{method:"GET"});if(!a.ok){const c=yield a.json().catch(()=>({error:a.statusText}));throw new Error(`Authorize failed: ${c.error_description||c.error||a.statusText}`)}const n=yield a.json();return k.parse(n)})}pollAuth(e){return d(this,null,function*(){const o={polling_code:e};w.parse(o);const r=yield fetch(p(this.config.ssoBaseUrl,"/oauth/poll"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(o)});if(!r.ok)throw new Error(`Poll failed: ${r.statusText}`);const s=yield r.json();return y.parse(s)})}exchangeToken(e){return d(this,null,function*(){const o=sessionStorage.getItem(i+"code_verifier");if(!o)throw new Error("Missing code verifier.");const r=new URLSearchParams({grant_type:"authorization_code",code:e,client_id:this.providerAddress,code_verifier:o}),s=yield fetch(p(this.config.ssoBaseUrl,"/oauth/token"),{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:r.toString()});if(!s.ok){const l=yield s.json().catch(()=>({error:s.statusText}));throw new Error(`Token exchange failed: ${l.error_description||l.error||s.statusText}`)}const a=yield s.json(),n=f.parse(a);localStorage.setItem(i+"access_token",n.access_token),localStorage.setItem(i+"id_token",n.id_token),localStorage.setItem(u,n.refresh_token);const c=Date.now()+n.expires_in*1e3;return localStorage.setItem(g,c.toString()),sessionStorage.removeItem(i+"code_verifier"),n})}verifyAuth(){return d(this,null,function*(){return this.withAutoRefresh(()=>d(this,null,function*(){const e=this.getAccessToken();if(!e)return null;const o=yield fetch(p(this.config.ssoBaseUrl,"/oauth/userinfo"),{method:"GET",headers:{Authorization:`Bearer ${e}`}});if(!o.ok){if(o.status===401){const s=new Error("Unauthorized");throw s.response={status:401},s}return null}const r=yield o.json();return z.parse(r)}))})}getAccessToken(){return localStorage.getItem(i+"access_token")}getIdToken(){return localStorage.getItem(i+"id_token")}getAuthData(){const e=this.getIdToken()||this.getAccessToken();if(!e)return null;const o=e.split(".");if(o.length!==3)return null;let r;try{const n=_(o[0]);r=JSON.parse(n)}catch(n){return null}if(r.alg!=="RS256"||r.typ!=="JWT")return null;let s;try{const n=JSON.parse(_(o[1]));s=T.parse(n)}catch(n){return null}return(Array.isArray(s.aud)?s.aud:[s.aud]).includes(this.providerAddress)?s:null}getSubject(){const e=this.getAuthData();return(e==null?void 0:e.sub)||null}isTokenExpired(){const e=this.getAuthData();return e?Date.now()/1e3>e.exp:!0}logout(){localStorage.removeItem(i+"access_token"),localStorage.removeItem(i+"id_token"),localStorage.removeItem(u),localStorage.removeItem(g),sessionStorage.removeItem(i+"code_verifier")}getRefreshToken(){return localStorage.getItem(u)}hasRefreshToken(){return!!this.getRefreshToken()}isAccessTokenExpired(){const e=localStorage.getItem(g);if(!e)return!0;const o=parseInt(e,10),r=Date.now(),s=300*1e3;return r>=o-s}refreshAccessToken(){return d(this,null,function*(){const e=this.getRefreshToken();if(!e)throw new Error("No refresh token available");const o=new URLSearchParams({grant_type:"refresh_token",refresh_token:e,client_id:this.providerAddress}),r=yield fetch(p(this.config.ssoBaseUrl,"/oauth/token"),{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:o.toString()});if(!r.ok){const c=yield r.json().catch(()=>({error:r.statusText}));throw this.logout(),new Error(`Token refresh failed: ${c.error_description||c.error||r.statusText}`)}const s=yield r.json(),a=f.parse(s);localStorage.setItem(i+"access_token",a.access_token),localStorage.setItem(i+"id_token",a.id_token),localStorage.setItem(u,a.refresh_token);const n=Date.now()+a.expires_in*1e3;return localStorage.setItem(g,n.toString()),a})}withAutoRefresh(e,o=1){return d(this,null,function*(){var r,s,a;try{return yield e()}catch(n){if((((r=n==null?void 0:n.response)==null?void 0:r.status)===401||((s=n==null?void 0:n.message)==null?void 0:s.includes("401"))||((a=n==null?void 0:n.message)==null?void 0:a.includes("Unauthorized")))&&o>0&&this.hasRefreshToken())try{return yield this.refreshAccessToken(),yield e()}catch(l){throw n}throw n}})}}exports.AlienSsoClient=v;exports.AlienSsoClientSchema=A;exports.AuthorizeResponseSchema=k;exports.ExchangeCodeResponseSchema=j;exports.PollRequestSchema=w;exports.PollResponseSchema=y;exports.TokenInfoSchema=T;exports.TokenResponseSchema=f;exports.UserInfoResponseSchema=z;
1
+ "use strict";var h=(d,e,o)=>new Promise((r,s)=>{var a=l=>{try{c(o.next(l))}catch(S){s(S)}},n=l=>{try{c(o.throw(l))}catch(S){s(S)}},c=l=>l.done?r(l.value):Promise.resolve(l.value).then(a,n);c((o=o.apply(d,e)).next())});Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("zod/v4-mini"),I=require("js-sha256"),y=t.z.object({deep_link:t.z.string(),polling_code:t.z.string(),expired_at:t.z.number()}),T=t.z.object({polling_code:t.z.string()}),j=["pending","authorized","rejected","expired"],x=t.z.enum(j),z=t.z.object({status:x,authorization_code:t.z.optional(t.z.string())}),m=t.z.object({access_token:t.z.string(),token_type:t.z.string(),expires_in:t.z.number(),id_token:t.z.string(),refresh_token:t.z.string()}),R=t.z.object({sub:t.z.string()}),A=t.z.object({iss:t.z.string(),sub:t.z.string(),aud:t.z.union([t.z.string(),t.z.array(t.z.string())]),exp:t.z.number(),iat:t.z.number(),nonce:t.z.optional(t.z.string()),auth_time:t.z.optional(t.z.number())}),E=m;function w(d){return btoa(d).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}function _(d){let e=d.replace(/-/g,"+").replace(/_/g,"/");for(;e.length%4;)e+="=";return atob(e)}const v="https://sso.alien.com",P=5e3,i="alien-sso_",g=i+"refresh_token",p=i+"token_expiry",f=(d,e)=>new URL(e,d).toString(),b=t.z.object({ssoBaseUrl:t.z.url(),providerAddress:t.z.string(),pollingInterval:t.z.optional(t.z.number())}),u=class u{constructor(e){this.config=b.parse(e),this.ssoBaseUrl=this.config.ssoBaseUrl||v,this.providerAddress=this.config.providerAddress,this.pollingInterval=this.config.pollingInterval||P}generateCodeVerifier(e=128){let o;const r=typeof window!="undefined"&&window.crypto;if(r&&r.getRandomValues)o=new Uint8Array(e),r.getRandomValues(o);else{o=new Uint8Array(e);for(let a=0;a<e;a++)o[a]=Math.floor(Math.random()*256)}let s="";for(let a=0;a<o.length;a++)s+=String.fromCharCode(o[a]);return w(s)}generateCodeChallenge(e){const o=I.sha256.array(e),r=String.fromCharCode(...o);return w(r)}generateDeeplink(){return h(this,null,function*(){const e=this.generateCodeVerifier(),o=this.generateCodeChallenge(e);sessionStorage.setItem(i+"code_verifier",e);const r=new URLSearchParams({response_type:"code",response_mode:"json",client_id:this.providerAddress,scope:"openid",code_challenge:o,code_challenge_method:"S256"}),s=`${this.config.ssoBaseUrl}/oauth/authorize?${r.toString()}`,a=yield fetch(s,{method:"GET"});if(!a.ok){const c=yield a.json().catch(()=>({error:a.statusText}));throw new Error(`Authorize failed: ${c.error_description||c.error||a.statusText}`)}const n=yield a.json();return y.parse(n)})}pollAuth(e){return h(this,null,function*(){const o={polling_code:e};T.parse(o);const r=yield fetch(f(this.config.ssoBaseUrl,"/oauth/poll"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(o)});if(!r.ok)throw new Error(`Poll failed: ${r.statusText}`);const s=yield r.json();return z.parse(s)})}exchangeToken(e){return h(this,null,function*(){const o=sessionStorage.getItem(i+"code_verifier");if(!o)throw new Error("Missing code verifier.");const r=new URLSearchParams({grant_type:"authorization_code",code:e,client_id:this.providerAddress,code_verifier:o}),s=yield fetch(f(this.config.ssoBaseUrl,"/oauth/token"),{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:r.toString()});if(!s.ok){const l=yield s.json().catch(()=>({error:s.statusText}));throw new Error(`Token exchange failed: ${l.error_description||l.error||s.statusText}`)}const a=yield s.json(),n=m.parse(a);localStorage.setItem(i+"access_token",n.access_token),localStorage.setItem(i+"id_token",n.id_token),localStorage.setItem(g,n.refresh_token);const c=Date.now()+n.expires_in*1e3;return localStorage.setItem(p,c.toString()),sessionStorage.removeItem(i+"code_verifier"),n})}verifyAuth(){return h(this,null,function*(){return this.withAutoRefresh(()=>h(this,null,function*(){const e=this.getAccessToken();if(!e)return null;const o=yield fetch(f(this.config.ssoBaseUrl,"/oauth/userinfo"),{method:"GET",headers:{Authorization:`Bearer ${e}`}});if(!o.ok){if(o.status===401){const s=new Error("Unauthorized");throw s.response={status:401},s}return null}const r=yield o.json();return R.parse(r)}))})}getAccessToken(){return localStorage.getItem(i+"access_token")}getIdToken(){return localStorage.getItem(i+"id_token")}getAuthData(){const e=this.getIdToken()||this.getAccessToken();if(!e)return null;const o=e.split(".");if(o.length!==3)return null;let r;try{const n=_(o[0]);r=JSON.parse(n)}catch(n){return null}if(r.alg!=="RS256"||r.typ!=="JWT")return null;let s;try{const n=JSON.parse(_(o[1]));s=A.parse(n)}catch(n){return null}return(Array.isArray(s.aud)?s.aud:[s.aud]).includes(this.providerAddress)?s:null}getSubject(){const e=this.getAuthData();return(e==null?void 0:e.sub)||null}isTokenExpired(){const e=this.getAuthData();return e?Date.now()/1e3>e.exp:!0}logout(){localStorage.removeItem(i+"access_token"),localStorage.removeItem(i+"id_token"),localStorage.removeItem(g),localStorage.removeItem(p),sessionStorage.removeItem(i+"code_verifier")}getRefreshToken(){return localStorage.getItem(g)}hasRefreshToken(){return!!this.getRefreshToken()}isAccessTokenExpired(){const e=localStorage.getItem(p);if(!e)return!0;const o=parseInt(e,10),r=Date.now(),s=300*1e3;return r>=o-s}refreshAccessToken(){return h(this,null,function*(){return u.refreshPromise||(u.refreshPromise=this.doRefreshAccessToken().finally(()=>{u.refreshPromise=null})),u.refreshPromise})}doRefreshAccessToken(){return h(this,null,function*(){const e=this.getRefreshToken();if(!e)throw new Error("No refresh token available");const o=new URLSearchParams({grant_type:"refresh_token",refresh_token:e,client_id:this.providerAddress}),r=yield fetch(f(this.config.ssoBaseUrl,"/oauth/token"),{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:o.toString()});if(!r.ok){const c=yield r.json().catch(()=>({error:r.statusText}));throw this.logout(),new Error(`Token refresh failed: ${c.error_description||c.error||r.statusText}`)}const s=yield r.json(),a=m.parse(s);localStorage.setItem(i+"access_token",a.access_token),localStorage.setItem(i+"id_token",a.id_token),localStorage.setItem(g,a.refresh_token);const n=Date.now()+a.expires_in*1e3;return localStorage.setItem(p,n.toString()),a})}withAutoRefresh(e,o=1){return h(this,null,function*(){var r,s,a;try{return yield e()}catch(n){if((((r=n==null?void 0:n.response)==null?void 0:r.status)===401||((s=n==null?void 0:n.message)==null?void 0:s.includes("401"))||((a=n==null?void 0:n.message)==null?void 0:a.includes("Unauthorized")))&&o>0&&this.hasRefreshToken())try{return yield this.refreshAccessToken(),yield e()}catch(l){throw n}throw n}})}};u.refreshPromise=null;let k=u;exports.AlienSsoClient=k;exports.AlienSsoClientSchema=b;exports.AuthorizeResponseSchema=y;exports.ExchangeCodeResponseSchema=E;exports.PollRequestSchema=T;exports.PollResponseSchema=z;exports.TokenInfoSchema=A;exports.TokenResponseSchema=m;exports.UserInfoResponseSchema=R;
package/dist/index.d.ts CHANGED
@@ -5,6 +5,7 @@ export declare class AlienSsoClient {
5
5
  readonly pollingInterval: number;
6
6
  readonly ssoBaseUrl: string;
7
7
  readonly providerAddress: string;
8
+ private static refreshPromise;
8
9
  constructor(config: AlienSsoClientConfig);
9
10
  private generateCodeVerifier;
10
11
  private generateCodeChallenge;
@@ -70,8 +71,13 @@ export declare class AlienSsoClient {
70
71
  /**
71
72
  * Refreshes the access token using the stored refresh token
72
73
  * POST /oauth/token with grant_type=refresh_token
74
+ * Uses singleton pattern to prevent concurrent refresh requests (race condition)
73
75
  */
74
76
  refreshAccessToken(): Promise<TokenResponse>;
77
+ /**
78
+ * Internal method that performs the actual token refresh
79
+ */
80
+ private doRefreshAccessToken;
75
81
  /**
76
82
  * Executes a function that makes an authenticated request
77
83
  * Automatically refreshes token and retries on 401 error
package/dist/index.esm.js CHANGED
@@ -1,39 +1,39 @@
1
- var d = (h, e, o) => new Promise((r, s) => {
1
+ var h = (u, e, r) => new Promise((o, s) => {
2
2
  var a = (l) => {
3
3
  try {
4
- c(o.next(l));
5
- } catch (f) {
6
- s(f);
4
+ c(r.next(l));
5
+ } catch (m) {
6
+ s(m);
7
7
  }
8
8
  }, n = (l) => {
9
9
  try {
10
- c(o.throw(l));
11
- } catch (f) {
12
- s(f);
10
+ c(r.throw(l));
11
+ } catch (m) {
12
+ s(m);
13
13
  }
14
- }, c = (l) => l.done ? r(l.value) : Promise.resolve(l.value).then(a, n);
15
- c((o = o.apply(h, e)).next());
14
+ }, c = (l) => l.done ? o(l.value) : Promise.resolve(l.value).then(a, n);
15
+ c((r = r.apply(u, e)).next());
16
16
  });
17
17
  import { z as t } from "zod/v4-mini";
18
- import { sha256 as S } from "js-sha256";
19
- const w = t.object({
18
+ import { sha256 as y } from "js-sha256";
19
+ const T = t.object({
20
20
  deep_link: t.string(),
21
21
  polling_code: t.string(),
22
22
  expired_at: t.number()
23
- }), y = t.object({
23
+ }), b = t.object({
24
24
  polling_code: t.string()
25
- }), T = ["pending", "authorized", "rejected", "expired"], A = t.enum(T), b = t.object({
26
- status: A,
25
+ }), A = ["pending", "authorized", "rejected", "expired"], I = t.enum(A), R = t.object({
26
+ status: I,
27
27
  authorization_code: t.optional(t.string())
28
- }), m = t.object({
28
+ }), k = t.object({
29
29
  access_token: t.string(),
30
30
  token_type: t.string(),
31
31
  expires_in: t.number(),
32
32
  id_token: t.string(),
33
33
  refresh_token: t.string()
34
- }), I = t.object({
34
+ }), x = t.object({
35
35
  sub: t.string()
36
- }), R = t.object({
36
+ }), j = t.object({
37
37
  iss: t.string(),
38
38
  sub: t.string(),
39
39
  aud: t.union([t.string(), t.array(t.string())]),
@@ -41,60 +41,59 @@ const w = t.object({
41
41
  iat: t.number(),
42
42
  nonce: t.optional(t.string()),
43
43
  auth_time: t.optional(t.number())
44
- }), P = m;
45
- function _(h) {
46
- return btoa(h).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
44
+ }), z = k;
45
+ function w(u) {
46
+ return btoa(u).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
47
47
  }
48
- function k(h) {
49
- let e = h.replace(/-/g, "+").replace(/_/g, "/");
48
+ function _(u) {
49
+ let e = u.replace(/-/g, "+").replace(/_/g, "/");
50
50
  for (; e.length % 4; )
51
51
  e += "=";
52
52
  return atob(e);
53
53
  }
54
- const x = "https://sso.alien.com", j = 5e3, i = "alien-sso_", u = i + "refresh_token", g = i + "token_expiry", p = (h, e) => new URL(e, h).toString(), E = t.object({
54
+ const E = "https://sso.alien.com", v = 5e3, i = "alien-sso_", g = i + "refresh_token", p = i + "token_expiry", f = (u, e) => new URL(e, u).toString(), U = t.object({
55
55
  ssoBaseUrl: t.url(),
56
56
  providerAddress: t.string(),
57
57
  pollingInterval: t.optional(t.number())
58
- });
59
- class O {
58
+ }), d = class d {
60
59
  constructor(e) {
61
- this.config = E.parse(e), this.ssoBaseUrl = this.config.ssoBaseUrl || x, this.providerAddress = this.config.providerAddress, this.pollingInterval = this.config.pollingInterval || j;
60
+ this.config = U.parse(e), this.ssoBaseUrl = this.config.ssoBaseUrl || E, this.providerAddress = this.config.providerAddress, this.pollingInterval = this.config.pollingInterval || v;
62
61
  }
63
62
  generateCodeVerifier(e = 128) {
64
- let o;
65
- const r = typeof window != "undefined" && window.crypto;
66
- if (r && r.getRandomValues)
67
- o = new Uint8Array(e), r.getRandomValues(o);
63
+ let r;
64
+ const o = typeof window != "undefined" && window.crypto;
65
+ if (o && o.getRandomValues)
66
+ r = new Uint8Array(e), o.getRandomValues(r);
68
67
  else {
69
- o = new Uint8Array(e);
68
+ r = new Uint8Array(e);
70
69
  for (let a = 0; a < e; a++)
71
- o[a] = Math.floor(Math.random() * 256);
70
+ r[a] = Math.floor(Math.random() * 256);
72
71
  }
73
72
  let s = "";
74
- for (let a = 0; a < o.length; a++)
75
- s += String.fromCharCode(o[a]);
76
- return _(s);
73
+ for (let a = 0; a < r.length; a++)
74
+ s += String.fromCharCode(r[a]);
75
+ return w(s);
77
76
  }
78
77
  generateCodeChallenge(e) {
79
- const o = S.array(e), r = String.fromCharCode(...o);
80
- return _(r);
78
+ const r = y.array(e), o = String.fromCharCode(...r);
79
+ return w(o);
81
80
  }
82
81
  /**
83
82
  * Initiates OAuth2 authorization flow with response_mode=json for SPA
84
83
  * GET /oauth/authorize?response_type=code&response_mode=json&...
85
84
  */
86
85
  generateDeeplink() {
87
- return d(this, null, function* () {
88
- const e = this.generateCodeVerifier(), o = this.generateCodeChallenge(e);
86
+ return h(this, null, function* () {
87
+ const e = this.generateCodeVerifier(), r = this.generateCodeChallenge(e);
89
88
  sessionStorage.setItem(i + "code_verifier", e);
90
- const r = new URLSearchParams({
89
+ const o = new URLSearchParams({
91
90
  response_type: "code",
92
91
  response_mode: "json",
93
92
  client_id: this.providerAddress,
94
93
  scope: "openid",
95
- code_challenge: o,
94
+ code_challenge: r,
96
95
  code_challenge_method: "S256"
97
- }), s = `${this.config.ssoBaseUrl}/oauth/authorize?${r.toString()}`, a = yield fetch(s, {
96
+ }), s = `${this.config.ssoBaseUrl}/oauth/authorize?${o.toString()}`, a = yield fetch(s, {
98
97
  method: "GET"
99
98
  });
100
99
  if (!a.ok) {
@@ -102,7 +101,7 @@ class O {
102
101
  throw new Error(`Authorize failed: ${c.error_description || c.error || a.statusText}`);
103
102
  }
104
103
  const n = yield a.json();
105
- return w.parse(n);
104
+ return T.parse(n);
106
105
  });
107
106
  }
108
107
  /**
@@ -110,22 +109,22 @@ class O {
110
109
  * POST /oauth/poll
111
110
  */
112
111
  pollAuth(e) {
113
- return d(this, null, function* () {
114
- const o = {
112
+ return h(this, null, function* () {
113
+ const r = {
115
114
  polling_code: e
116
115
  };
117
- y.parse(o);
118
- const r = yield fetch(p(this.config.ssoBaseUrl, "/oauth/poll"), {
116
+ b.parse(r);
117
+ const o = yield fetch(f(this.config.ssoBaseUrl, "/oauth/poll"), {
119
118
  method: "POST",
120
119
  headers: {
121
120
  "Content-Type": "application/json"
122
121
  },
123
- body: JSON.stringify(o)
122
+ body: JSON.stringify(r)
124
123
  });
125
- if (!r.ok)
126
- throw new Error(`Poll failed: ${r.statusText}`);
127
- const s = yield r.json();
128
- return b.parse(s);
124
+ if (!o.ok)
125
+ throw new Error(`Poll failed: ${o.statusText}`);
126
+ const s = yield o.json();
127
+ return R.parse(s);
129
128
  });
130
129
  }
131
130
  /**
@@ -134,32 +133,32 @@ class O {
134
133
  * Returns both access_token and id_token
135
134
  */
136
135
  exchangeToken(e) {
137
- return d(this, null, function* () {
138
- const o = sessionStorage.getItem(i + "code_verifier");
139
- if (!o) throw new Error("Missing code verifier.");
140
- const r = new URLSearchParams({
136
+ return h(this, null, function* () {
137
+ const r = sessionStorage.getItem(i + "code_verifier");
138
+ if (!r) throw new Error("Missing code verifier.");
139
+ const o = new URLSearchParams({
141
140
  grant_type: "authorization_code",
142
141
  code: e,
143
142
  client_id: this.providerAddress,
144
- code_verifier: o
143
+ code_verifier: r
145
144
  }), s = yield fetch(
146
- p(this.config.ssoBaseUrl, "/oauth/token"),
145
+ f(this.config.ssoBaseUrl, "/oauth/token"),
147
146
  {
148
147
  method: "POST",
149
148
  headers: {
150
149
  "Content-Type": "application/x-www-form-urlencoded"
151
150
  },
152
- body: r.toString()
151
+ body: o.toString()
153
152
  }
154
153
  );
155
154
  if (!s.ok) {
156
155
  const l = yield s.json().catch(() => ({ error: s.statusText }));
157
156
  throw new Error(`Token exchange failed: ${l.error_description || l.error || s.statusText}`);
158
157
  }
159
- const a = yield s.json(), n = m.parse(a);
160
- localStorage.setItem(i + "access_token", n.access_token), localStorage.setItem(i + "id_token", n.id_token), localStorage.setItem(u, n.refresh_token);
158
+ const a = yield s.json(), n = k.parse(a);
159
+ localStorage.setItem(i + "access_token", n.access_token), localStorage.setItem(i + "id_token", n.id_token), localStorage.setItem(g, n.refresh_token);
161
160
  const c = Date.now() + n.expires_in * 1e3;
162
- return localStorage.setItem(g, c.toString()), sessionStorage.removeItem(i + "code_verifier"), n;
161
+ return localStorage.setItem(p, c.toString()), sessionStorage.removeItem(i + "code_verifier"), n;
163
162
  });
164
163
  }
165
164
  /**
@@ -168,13 +167,13 @@ class O {
168
167
  * Automatically refreshes token on 401 if refresh token is available
169
168
  */
170
169
  verifyAuth() {
171
- return d(this, null, function* () {
172
- return this.withAutoRefresh(() => d(this, null, function* () {
170
+ return h(this, null, function* () {
171
+ return this.withAutoRefresh(() => h(this, null, function* () {
173
172
  const e = this.getAccessToken();
174
173
  if (!e)
175
174
  return null;
176
- const o = yield fetch(
177
- p(this.config.ssoBaseUrl, "/oauth/userinfo"),
175
+ const r = yield fetch(
176
+ f(this.config.ssoBaseUrl, "/oauth/userinfo"),
178
177
  {
179
178
  method: "GET",
180
179
  headers: {
@@ -182,15 +181,15 @@ class O {
182
181
  }
183
182
  }
184
183
  );
185
- if (!o.ok) {
186
- if (o.status === 401) {
184
+ if (!r.ok) {
185
+ if (r.status === 401) {
187
186
  const s = new Error("Unauthorized");
188
187
  throw s.response = { status: 401 }, s;
189
188
  }
190
189
  return null;
191
190
  }
192
- const r = yield o.json();
193
- return I.parse(r);
191
+ const o = yield r.json();
192
+ return x.parse(o);
194
193
  }));
195
194
  });
196
195
  }
@@ -213,22 +212,22 @@ class O {
213
212
  getAuthData() {
214
213
  const e = this.getIdToken() || this.getAccessToken();
215
214
  if (!e) return null;
216
- const o = e.split(".");
217
- if (o.length !== 3)
215
+ const r = e.split(".");
216
+ if (r.length !== 3)
218
217
  return null;
219
- let r;
218
+ let o;
220
219
  try {
221
- const n = k(o[0]);
222
- r = JSON.parse(n);
220
+ const n = _(r[0]);
221
+ o = JSON.parse(n);
223
222
  } catch (n) {
224
223
  return null;
225
224
  }
226
- if (r.alg !== "RS256" || r.typ !== "JWT")
225
+ if (o.alg !== "RS256" || o.typ !== "JWT")
227
226
  return null;
228
227
  let s;
229
228
  try {
230
- const n = JSON.parse(k(o[1]));
231
- s = R.parse(n);
229
+ const n = JSON.parse(_(r[1]));
230
+ s = j.parse(n);
232
231
  } catch (n) {
233
232
  return null;
234
233
  }
@@ -252,13 +251,13 @@ class O {
252
251
  * Clears all stored authentication data
253
252
  */
254
253
  logout() {
255
- localStorage.removeItem(i + "access_token"), localStorage.removeItem(i + "id_token"), localStorage.removeItem(u), localStorage.removeItem(g), sessionStorage.removeItem(i + "code_verifier");
254
+ localStorage.removeItem(i + "access_token"), localStorage.removeItem(i + "id_token"), localStorage.removeItem(g), localStorage.removeItem(p), sessionStorage.removeItem(i + "code_verifier");
256
255
  }
257
256
  /**
258
257
  * Gets stored refresh token
259
258
  */
260
259
  getRefreshToken() {
261
- return localStorage.getItem(u);
260
+ return localStorage.getItem(g);
262
261
  }
263
262
  /**
264
263
  * Checks if a refresh token is available
@@ -270,55 +269,66 @@ class O {
270
269
  * Checks if the access token is expired or will expire soon (within 5 minutes)
271
270
  */
272
271
  isAccessTokenExpired() {
273
- const e = localStorage.getItem(g);
272
+ const e = localStorage.getItem(p);
274
273
  if (!e) return !0;
275
- const o = parseInt(e, 10), r = Date.now(), s = 300 * 1e3;
276
- return r >= o - s;
274
+ const r = parseInt(e, 10), o = Date.now(), s = 300 * 1e3;
275
+ return o >= r - s;
277
276
  }
278
277
  /**
279
278
  * Refreshes the access token using the stored refresh token
280
279
  * POST /oauth/token with grant_type=refresh_token
280
+ * Uses singleton pattern to prevent concurrent refresh requests (race condition)
281
281
  */
282
282
  refreshAccessToken() {
283
- return d(this, null, function* () {
283
+ return h(this, null, function* () {
284
+ return d.refreshPromise || (d.refreshPromise = this.doRefreshAccessToken().finally(() => {
285
+ d.refreshPromise = null;
286
+ })), d.refreshPromise;
287
+ });
288
+ }
289
+ /**
290
+ * Internal method that performs the actual token refresh
291
+ */
292
+ doRefreshAccessToken() {
293
+ return h(this, null, function* () {
284
294
  const e = this.getRefreshToken();
285
295
  if (!e)
286
296
  throw new Error("No refresh token available");
287
- const o = new URLSearchParams({
297
+ const r = new URLSearchParams({
288
298
  grant_type: "refresh_token",
289
299
  refresh_token: e,
290
300
  client_id: this.providerAddress
291
- }), r = yield fetch(
292
- p(this.config.ssoBaseUrl, "/oauth/token"),
301
+ }), o = yield fetch(
302
+ f(this.config.ssoBaseUrl, "/oauth/token"),
293
303
  {
294
304
  method: "POST",
295
305
  headers: {
296
306
  "Content-Type": "application/x-www-form-urlencoded"
297
307
  },
298
- body: o.toString()
308
+ body: r.toString()
299
309
  }
300
310
  );
301
- if (!r.ok) {
302
- const c = yield r.json().catch(() => ({ error: r.statusText }));
303
- throw this.logout(), new Error(`Token refresh failed: ${c.error_description || c.error || r.statusText}`);
311
+ if (!o.ok) {
312
+ const c = yield o.json().catch(() => ({ error: o.statusText }));
313
+ throw this.logout(), new Error(`Token refresh failed: ${c.error_description || c.error || o.statusText}`);
304
314
  }
305
- const s = yield r.json(), a = m.parse(s);
306
- localStorage.setItem(i + "access_token", a.access_token), localStorage.setItem(i + "id_token", a.id_token), localStorage.setItem(u, a.refresh_token);
315
+ const s = yield o.json(), a = k.parse(s);
316
+ localStorage.setItem(i + "access_token", a.access_token), localStorage.setItem(i + "id_token", a.id_token), localStorage.setItem(g, a.refresh_token);
307
317
  const n = Date.now() + a.expires_in * 1e3;
308
- return localStorage.setItem(g, n.toString()), a;
318
+ return localStorage.setItem(p, n.toString()), a;
309
319
  });
310
320
  }
311
321
  /**
312
322
  * Executes a function that makes an authenticated request
313
323
  * Automatically refreshes token and retries on 401 error
314
324
  */
315
- withAutoRefresh(e, o = 1) {
316
- return d(this, null, function* () {
317
- var r, s, a;
325
+ withAutoRefresh(e, r = 1) {
326
+ return h(this, null, function* () {
327
+ var o, s, a;
318
328
  try {
319
329
  return yield e();
320
330
  } catch (n) {
321
- if ((((r = n == null ? void 0 : n.response) == null ? void 0 : r.status) === 401 || ((s = n == null ? void 0 : n.message) == null ? void 0 : s.includes("401")) || ((a = n == null ? void 0 : n.message) == null ? void 0 : a.includes("Unauthorized"))) && o > 0 && this.hasRefreshToken())
331
+ if ((((o = n == null ? void 0 : n.response) == null ? void 0 : o.status) === 401 || ((s = n == null ? void 0 : n.message) == null ? void 0 : s.includes("401")) || ((a = n == null ? void 0 : n.message) == null ? void 0 : a.includes("Unauthorized"))) && r > 0 && this.hasRefreshToken())
322
332
  try {
323
333
  return yield this.refreshAccessToken(), yield e();
324
334
  } catch (l) {
@@ -328,15 +338,17 @@ class O {
328
338
  }
329
339
  });
330
340
  }
331
- }
341
+ };
342
+ d.refreshPromise = null;
343
+ let S = d;
332
344
  export {
333
- O as AlienSsoClient,
334
- E as AlienSsoClientSchema,
335
- w as AuthorizeResponseSchema,
336
- P as ExchangeCodeResponseSchema,
337
- y as PollRequestSchema,
338
- b as PollResponseSchema,
339
- R as TokenInfoSchema,
340
- m as TokenResponseSchema,
341
- I as UserInfoResponseSchema
345
+ S as AlienSsoClient,
346
+ U as AlienSsoClientSchema,
347
+ T as AuthorizeResponseSchema,
348
+ z as ExchangeCodeResponseSchema,
349
+ b as PollRequestSchema,
350
+ R as PollResponseSchema,
351
+ j as TokenInfoSchema,
352
+ k as TokenResponseSchema,
353
+ x as UserInfoResponseSchema
342
354
  };
package/dist/index.umd.js CHANGED
@@ -1 +1 @@
1
- (function(c,t){typeof exports=="object"&&typeof module!="undefined"?t(exports,require("zod/v4-mini"),require("js-sha256")):typeof define=="function"&&define.amd?define(["exports","zod/v4-mini","js-sha256"],t):(c=typeof globalThis!="undefined"?globalThis:c||self,t(c.AlienSsoCore={},c.Zod,c.jsSha256))})(this,(function(c,t,u){"use strict";var d=(c,t,u)=>new Promise((S,m)=>{var y=l=>{try{g(u.next(l))}catch(p){m(p)}},z=l=>{try{g(u.throw(l))}catch(p){m(p)}},g=l=>l.done?S(l.value):Promise.resolve(l.value).then(y,z);g((u=u.apply(c,t)).next())});const S=t.z.object({deep_link:t.z.string(),polling_code:t.z.string(),expired_at:t.z.number()}),m=t.z.object({polling_code:t.z.string()}),y=["pending","authorized","rejected","expired"],z=t.z.enum(y),g=t.z.object({status:z,authorization_code:t.z.optional(t.z.string())}),l=t.z.object({access_token:t.z.string(),token_type:t.z.string(),expires_in:t.z.number(),id_token:t.z.string(),refresh_token:t.z.string()}),p=t.z.object({sub:t.z.string()}),A=t.z.object({iss:t.z.string(),sub:t.z.string(),aud:t.z.union([t.z.string(),t.z.array(t.z.string())]),exp:t.z.number(),iat:t.z.number(),nonce:t.z.optional(t.z.string()),auth_time:t.z.optional(t.z.number())}),j=l;function R(f){return btoa(f).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}function b(f){let e=f.replace(/-/g,"+").replace(/_/g,"/");for(;e.length%4;)e+="=";return atob(e)}const E="https://sso.alien.com",x=5e3,i="alien-sso_",_=i+"refresh_token",k=i+"token_expiry",w=(f,e)=>new URL(e,f).toString(),I=t.z.object({ssoBaseUrl:t.z.url(),providerAddress:t.z.string(),pollingInterval:t.z.optional(t.z.number())});class C{constructor(e){this.config=I.parse(e),this.ssoBaseUrl=this.config.ssoBaseUrl||E,this.providerAddress=this.config.providerAddress,this.pollingInterval=this.config.pollingInterval||x}generateCodeVerifier(e=128){let o;const s=typeof window!="undefined"&&window.crypto;if(s&&s.getRandomValues)o=new Uint8Array(e),s.getRandomValues(o);else{o=new Uint8Array(e);for(let a=0;a<e;a++)o[a]=Math.floor(Math.random()*256)}let r="";for(let a=0;a<o.length;a++)r+=String.fromCharCode(o[a]);return R(r)}generateCodeChallenge(e){const o=u.sha256.array(e),s=String.fromCharCode(...o);return R(s)}generateDeeplink(){return d(this,null,function*(){const e=this.generateCodeVerifier(),o=this.generateCodeChallenge(e);sessionStorage.setItem(i+"code_verifier",e);const s=new URLSearchParams({response_type:"code",response_mode:"json",client_id:this.providerAddress,scope:"openid",code_challenge:o,code_challenge_method:"S256"}),r=`${this.config.ssoBaseUrl}/oauth/authorize?${s.toString()}`,a=yield fetch(r,{method:"GET"});if(!a.ok){const h=yield a.json().catch(()=>({error:a.statusText}));throw new Error(`Authorize failed: ${h.error_description||h.error||a.statusText}`)}const n=yield a.json();return S.parse(n)})}pollAuth(e){return d(this,null,function*(){const o={polling_code:e};m.parse(o);const s=yield fetch(w(this.config.ssoBaseUrl,"/oauth/poll"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(o)});if(!s.ok)throw new Error(`Poll failed: ${s.statusText}`);const r=yield s.json();return g.parse(r)})}exchangeToken(e){return d(this,null,function*(){const o=sessionStorage.getItem(i+"code_verifier");if(!o)throw new Error("Missing code verifier.");const s=new URLSearchParams({grant_type:"authorization_code",code:e,client_id:this.providerAddress,code_verifier:o}),r=yield fetch(w(this.config.ssoBaseUrl,"/oauth/token"),{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:s.toString()});if(!r.ok){const T=yield r.json().catch(()=>({error:r.statusText}));throw new Error(`Token exchange failed: ${T.error_description||T.error||r.statusText}`)}const a=yield r.json(),n=l.parse(a);localStorage.setItem(i+"access_token",n.access_token),localStorage.setItem(i+"id_token",n.id_token),localStorage.setItem(_,n.refresh_token);const h=Date.now()+n.expires_in*1e3;return localStorage.setItem(k,h.toString()),sessionStorage.removeItem(i+"code_verifier"),n})}verifyAuth(){return d(this,null,function*(){return this.withAutoRefresh(()=>d(this,null,function*(){const e=this.getAccessToken();if(!e)return null;const o=yield fetch(w(this.config.ssoBaseUrl,"/oauth/userinfo"),{method:"GET",headers:{Authorization:`Bearer ${e}`}});if(!o.ok){if(o.status===401){const r=new Error("Unauthorized");throw r.response={status:401},r}return null}const s=yield o.json();return p.parse(s)}))})}getAccessToken(){return localStorage.getItem(i+"access_token")}getIdToken(){return localStorage.getItem(i+"id_token")}getAuthData(){const e=this.getIdToken()||this.getAccessToken();if(!e)return null;const o=e.split(".");if(o.length!==3)return null;let s;try{const n=b(o[0]);s=JSON.parse(n)}catch(n){return null}if(s.alg!=="RS256"||s.typ!=="JWT")return null;let r;try{const n=JSON.parse(b(o[1]));r=A.parse(n)}catch(n){return null}return(Array.isArray(r.aud)?r.aud:[r.aud]).includes(this.providerAddress)?r:null}getSubject(){const e=this.getAuthData();return(e==null?void 0:e.sub)||null}isTokenExpired(){const e=this.getAuthData();return e?Date.now()/1e3>e.exp:!0}logout(){localStorage.removeItem(i+"access_token"),localStorage.removeItem(i+"id_token"),localStorage.removeItem(_),localStorage.removeItem(k),sessionStorage.removeItem(i+"code_verifier")}getRefreshToken(){return localStorage.getItem(_)}hasRefreshToken(){return!!this.getRefreshToken()}isAccessTokenExpired(){const e=localStorage.getItem(k);if(!e)return!0;const o=parseInt(e,10),s=Date.now(),r=300*1e3;return s>=o-r}refreshAccessToken(){return d(this,null,function*(){const e=this.getRefreshToken();if(!e)throw new Error("No refresh token available");const o=new URLSearchParams({grant_type:"refresh_token",refresh_token:e,client_id:this.providerAddress}),s=yield fetch(w(this.config.ssoBaseUrl,"/oauth/token"),{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:o.toString()});if(!s.ok){const h=yield s.json().catch(()=>({error:s.statusText}));throw this.logout(),new Error(`Token refresh failed: ${h.error_description||h.error||s.statusText}`)}const r=yield s.json(),a=l.parse(r);localStorage.setItem(i+"access_token",a.access_token),localStorage.setItem(i+"id_token",a.id_token),localStorage.setItem(_,a.refresh_token);const n=Date.now()+a.expires_in*1e3;return localStorage.setItem(k,n.toString()),a})}withAutoRefresh(e,o=1){return d(this,null,function*(){var s,r,a;try{return yield e()}catch(n){if((((s=n==null?void 0:n.response)==null?void 0:s.status)===401||((r=n==null?void 0:n.message)==null?void 0:r.includes("401"))||((a=n==null?void 0:n.message)==null?void 0:a.includes("Unauthorized")))&&o>0&&this.hasRefreshToken())try{return yield this.refreshAccessToken(),yield e()}catch(T){throw n}throw n}})}}c.AlienSsoClient=C,c.AlienSsoClientSchema=I,c.AuthorizeResponseSchema=S,c.ExchangeCodeResponseSchema=j,c.PollRequestSchema=m,c.PollResponseSchema=g,c.TokenInfoSchema=A,c.TokenResponseSchema=l,c.UserInfoResponseSchema=p,Object.defineProperty(c,Symbol.toStringTag,{value:"Module"})}));
1
+ (function(c,t){typeof exports=="object"&&typeof module!="undefined"?t(exports,require("zod/v4-mini"),require("js-sha256")):typeof define=="function"&&define.amd?define(["exports","zod/v4-mini","js-sha256"],t):(c=typeof globalThis!="undefined"?globalThis:c||self,t(c.AlienSsoCore={},c.Zod,c.jsSha256))})(this,(function(c,t,g){"use strict";var h=(c,t,g)=>new Promise((k,m)=>{var T=l=>{try{f(g.next(l))}catch(p){m(p)}},z=l=>{try{f(g.throw(l))}catch(p){m(p)}},f=l=>l.done?k(l.value):Promise.resolve(l.value).then(T,z);f((g=g.apply(c,t)).next())});const k=t.z.object({deep_link:t.z.string(),polling_code:t.z.string(),expired_at:t.z.number()}),m=t.z.object({polling_code:t.z.string()}),T=["pending","authorized","rejected","expired"],z=t.z.enum(T),f=t.z.object({status:z,authorization_code:t.z.optional(t.z.string())}),l=t.z.object({access_token:t.z.string(),token_type:t.z.string(),expires_in:t.z.number(),id_token:t.z.string(),refresh_token:t.z.string()}),p=t.z.object({sub:t.z.string()}),b=t.z.object({iss:t.z.string(),sub:t.z.string(),aud:t.z.union([t.z.string(),t.z.array(t.z.string())]),exp:t.z.number(),iat:t.z.number(),nonce:t.z.optional(t.z.string()),auth_time:t.z.optional(t.z.number())}),P=l;function I(S){return btoa(S).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}function j(S){let e=S.replace(/-/g,"+").replace(/_/g,"/");for(;e.length%4;)e+="=";return atob(e)}const x="https://sso.alien.com",U=5e3,i="alien-sso_",w=i+"refresh_token",_=i+"token_expiry",y=(S,e)=>new URL(e,S).toString(),E=t.z.object({ssoBaseUrl:t.z.url(),providerAddress:t.z.string(),pollingInterval:t.z.optional(t.z.number())}),d=class d{constructor(e){this.config=E.parse(e),this.ssoBaseUrl=this.config.ssoBaseUrl||x,this.providerAddress=this.config.providerAddress,this.pollingInterval=this.config.pollingInterval||U}generateCodeVerifier(e=128){let o;const r=typeof window!="undefined"&&window.crypto;if(r&&r.getRandomValues)o=new Uint8Array(e),r.getRandomValues(o);else{o=new Uint8Array(e);for(let a=0;a<e;a++)o[a]=Math.floor(Math.random()*256)}let s="";for(let a=0;a<o.length;a++)s+=String.fromCharCode(o[a]);return I(s)}generateCodeChallenge(e){const o=g.sha256.array(e),r=String.fromCharCode(...o);return I(r)}generateDeeplink(){return h(this,null,function*(){const e=this.generateCodeVerifier(),o=this.generateCodeChallenge(e);sessionStorage.setItem(i+"code_verifier",e);const r=new URLSearchParams({response_type:"code",response_mode:"json",client_id:this.providerAddress,scope:"openid",code_challenge:o,code_challenge_method:"S256"}),s=`${this.config.ssoBaseUrl}/oauth/authorize?${r.toString()}`,a=yield fetch(s,{method:"GET"});if(!a.ok){const u=yield a.json().catch(()=>({error:a.statusText}));throw new Error(`Authorize failed: ${u.error_description||u.error||a.statusText}`)}const n=yield a.json();return k.parse(n)})}pollAuth(e){return h(this,null,function*(){const o={polling_code:e};m.parse(o);const r=yield fetch(y(this.config.ssoBaseUrl,"/oauth/poll"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(o)});if(!r.ok)throw new Error(`Poll failed: ${r.statusText}`);const s=yield r.json();return f.parse(s)})}exchangeToken(e){return h(this,null,function*(){const o=sessionStorage.getItem(i+"code_verifier");if(!o)throw new Error("Missing code verifier.");const r=new URLSearchParams({grant_type:"authorization_code",code:e,client_id:this.providerAddress,code_verifier:o}),s=yield fetch(y(this.config.ssoBaseUrl,"/oauth/token"),{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:r.toString()});if(!s.ok){const R=yield s.json().catch(()=>({error:s.statusText}));throw new Error(`Token exchange failed: ${R.error_description||R.error||s.statusText}`)}const a=yield s.json(),n=l.parse(a);localStorage.setItem(i+"access_token",n.access_token),localStorage.setItem(i+"id_token",n.id_token),localStorage.setItem(w,n.refresh_token);const u=Date.now()+n.expires_in*1e3;return localStorage.setItem(_,u.toString()),sessionStorage.removeItem(i+"code_verifier"),n})}verifyAuth(){return h(this,null,function*(){return this.withAutoRefresh(()=>h(this,null,function*(){const e=this.getAccessToken();if(!e)return null;const o=yield fetch(y(this.config.ssoBaseUrl,"/oauth/userinfo"),{method:"GET",headers:{Authorization:`Bearer ${e}`}});if(!o.ok){if(o.status===401){const s=new Error("Unauthorized");throw s.response={status:401},s}return null}const r=yield o.json();return p.parse(r)}))})}getAccessToken(){return localStorage.getItem(i+"access_token")}getIdToken(){return localStorage.getItem(i+"id_token")}getAuthData(){const e=this.getIdToken()||this.getAccessToken();if(!e)return null;const o=e.split(".");if(o.length!==3)return null;let r;try{const n=j(o[0]);r=JSON.parse(n)}catch(n){return null}if(r.alg!=="RS256"||r.typ!=="JWT")return null;let s;try{const n=JSON.parse(j(o[1]));s=b.parse(n)}catch(n){return null}return(Array.isArray(s.aud)?s.aud:[s.aud]).includes(this.providerAddress)?s:null}getSubject(){const e=this.getAuthData();return(e==null?void 0:e.sub)||null}isTokenExpired(){const e=this.getAuthData();return e?Date.now()/1e3>e.exp:!0}logout(){localStorage.removeItem(i+"access_token"),localStorage.removeItem(i+"id_token"),localStorage.removeItem(w),localStorage.removeItem(_),sessionStorage.removeItem(i+"code_verifier")}getRefreshToken(){return localStorage.getItem(w)}hasRefreshToken(){return!!this.getRefreshToken()}isAccessTokenExpired(){const e=localStorage.getItem(_);if(!e)return!0;const o=parseInt(e,10),r=Date.now(),s=300*1e3;return r>=o-s}refreshAccessToken(){return h(this,null,function*(){return d.refreshPromise||(d.refreshPromise=this.doRefreshAccessToken().finally(()=>{d.refreshPromise=null})),d.refreshPromise})}doRefreshAccessToken(){return h(this,null,function*(){const e=this.getRefreshToken();if(!e)throw new Error("No refresh token available");const o=new URLSearchParams({grant_type:"refresh_token",refresh_token:e,client_id:this.providerAddress}),r=yield fetch(y(this.config.ssoBaseUrl,"/oauth/token"),{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:o.toString()});if(!r.ok){const u=yield r.json().catch(()=>({error:r.statusText}));throw this.logout(),new Error(`Token refresh failed: ${u.error_description||u.error||r.statusText}`)}const s=yield r.json(),a=l.parse(s);localStorage.setItem(i+"access_token",a.access_token),localStorage.setItem(i+"id_token",a.id_token),localStorage.setItem(w,a.refresh_token);const n=Date.now()+a.expires_in*1e3;return localStorage.setItem(_,n.toString()),a})}withAutoRefresh(e,o=1){return h(this,null,function*(){var r,s,a;try{return yield e()}catch(n){if((((r=n==null?void 0:n.response)==null?void 0:r.status)===401||((s=n==null?void 0:n.message)==null?void 0:s.includes("401"))||((a=n==null?void 0:n.message)==null?void 0:a.includes("Unauthorized")))&&o>0&&this.hasRefreshToken())try{return yield this.refreshAccessToken(),yield e()}catch(R){throw n}throw n}})}};d.refreshPromise=null;let A=d;c.AlienSsoClient=A,c.AlienSsoClientSchema=E,c.AuthorizeResponseSchema=k,c.ExchangeCodeResponseSchema=P,c.PollRequestSchema=m,c.PollResponseSchema=f,c.TokenInfoSchema=b,c.TokenResponseSchema=l,c.UserInfoResponseSchema=p,Object.defineProperty(c,Symbol.toStringTag,{value:"Module"})}));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alien_org/sso-sdk-core",
3
- "version": "1.0.19",
3
+ "version": "1.0.20",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/alien-id/sso-sdk-js.git"