@alien_org/sso-sdk-core 1.0.18 → 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 +1 -1
- package/dist/index.d.ts +104 -33
- package/dist/index.esm.js +303 -174
- package/dist/index.umd.js +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
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,16 +5,84 @@ 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;
|
|
12
|
+
/**
|
|
13
|
+
* Initiates OAuth2 authorization flow with response_mode=json for SPA
|
|
14
|
+
* GET /oauth/authorize?response_type=code&response_mode=json&...
|
|
15
|
+
*/
|
|
11
16
|
generateDeeplink(): Promise<AuthorizeResponse>;
|
|
17
|
+
/**
|
|
18
|
+
* Polls for authorization completion
|
|
19
|
+
* POST /oauth/poll
|
|
20
|
+
*/
|
|
12
21
|
pollAuth(pollingCode: string): Promise<PollResponse>;
|
|
13
|
-
|
|
14
|
-
|
|
22
|
+
/**
|
|
23
|
+
* Exchanges authorization code for tokens
|
|
24
|
+
* POST /oauth/token (application/x-www-form-urlencoded)
|
|
25
|
+
* Returns both access_token and id_token
|
|
26
|
+
*/
|
|
27
|
+
exchangeToken(authorizationCode: string): Promise<TokenResponse>;
|
|
28
|
+
/**
|
|
29
|
+
* Verifies authentication by calling userinfo endpoint
|
|
30
|
+
* GET /oauth/userinfo
|
|
31
|
+
* Automatically refreshes token on 401 if refresh token is available
|
|
32
|
+
*/
|
|
33
|
+
verifyAuth(): Promise<UserInfoResponse | null>;
|
|
34
|
+
/**
|
|
35
|
+
* Gets stored access token
|
|
36
|
+
*/
|
|
15
37
|
getAccessToken(): string | null;
|
|
38
|
+
/**
|
|
39
|
+
* Gets stored ID token
|
|
40
|
+
*/
|
|
41
|
+
getIdToken(): string | null;
|
|
42
|
+
/**
|
|
43
|
+
* Decodes and validates JWT token to extract claims
|
|
44
|
+
* Works with both access_token and id_token (EdDSA signed)
|
|
45
|
+
*/
|
|
16
46
|
getAuthData(): TokenInfo | null;
|
|
47
|
+
/**
|
|
48
|
+
* Gets the subject (user identifier) from the token
|
|
49
|
+
*/
|
|
50
|
+
getSubject(): string | null;
|
|
51
|
+
/**
|
|
52
|
+
* Checks if the current token is expired
|
|
53
|
+
*/
|
|
54
|
+
isTokenExpired(): boolean;
|
|
55
|
+
/**
|
|
56
|
+
* Clears all stored authentication data
|
|
57
|
+
*/
|
|
17
58
|
logout(): void;
|
|
59
|
+
/**
|
|
60
|
+
* Gets stored refresh token
|
|
61
|
+
*/
|
|
62
|
+
getRefreshToken(): string | null;
|
|
63
|
+
/**
|
|
64
|
+
* Checks if a refresh token is available
|
|
65
|
+
*/
|
|
66
|
+
hasRefreshToken(): boolean;
|
|
67
|
+
/**
|
|
68
|
+
* Checks if the access token is expired or will expire soon (within 5 minutes)
|
|
69
|
+
*/
|
|
70
|
+
isAccessTokenExpired(): boolean;
|
|
71
|
+
/**
|
|
72
|
+
* Refreshes the access token using the stored refresh token
|
|
73
|
+
* POST /oauth/token with grant_type=refresh_token
|
|
74
|
+
* Uses singleton pattern to prevent concurrent refresh requests (race condition)
|
|
75
|
+
*/
|
|
76
|
+
refreshAccessToken(): Promise<TokenResponse>;
|
|
77
|
+
/**
|
|
78
|
+
* Internal method that performs the actual token refresh
|
|
79
|
+
*/
|
|
80
|
+
private doRefreshAccessToken;
|
|
81
|
+
/**
|
|
82
|
+
* Executes a function that makes an authenticated request
|
|
83
|
+
* Automatically refreshes token and retries on 401 error
|
|
84
|
+
*/
|
|
85
|
+
withAutoRefresh<T>(requestFn: () => Promise<T>, maxRetries?: number): Promise<T>;
|
|
18
86
|
}
|
|
19
87
|
|
|
20
88
|
export declare type AlienSsoClientConfig = z.infer<typeof AlienSsoClientSchema>;
|
|
@@ -25,49 +93,39 @@ export declare const AlienSsoClientSchema: z.ZodMiniObject<{
|
|
|
25
93
|
pollingInterval: z.ZodMiniOptional<z.ZodMiniNumber<number>>;
|
|
26
94
|
}, z.core.$strip>;
|
|
27
95
|
|
|
28
|
-
export declare type
|
|
96
|
+
export declare type AuthorizeResponse = z.infer<typeof AuthorizeResponseSchema>;
|
|
29
97
|
|
|
30
98
|
/**
|
|
31
|
-
* Authorize
|
|
99
|
+
* Authorize response schema (for response_mode=json)
|
|
100
|
+
* GET /oauth/authorize?response_mode=json&...
|
|
32
101
|
*/
|
|
33
|
-
export declare const AuthorizeRequestSchema: z.ZodMiniObject<{
|
|
34
|
-
code_challenge: z.ZodMiniString<string>;
|
|
35
|
-
code_challenge_method: z.ZodMiniLiteral<"S256">;
|
|
36
|
-
}, z.core.$strip>;
|
|
37
|
-
|
|
38
|
-
export declare type AuthorizeResponse = z.infer<typeof AuthorizeResponseSchema>;
|
|
39
|
-
|
|
40
102
|
export declare const AuthorizeResponseSchema: z.ZodMiniObject<{
|
|
41
103
|
deep_link: z.ZodMiniString<string>;
|
|
42
104
|
polling_code: z.ZodMiniString<string>;
|
|
43
105
|
expired_at: z.ZodMiniNumber<number>;
|
|
44
106
|
}, z.core.$strip>;
|
|
45
107
|
|
|
46
|
-
export declare type
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* ExchangeCode request/response schema
|
|
50
|
-
*/
|
|
51
|
-
export declare const ExchangeCodeRequestSchema: z.ZodMiniObject<{
|
|
52
|
-
authorization_code: z.ZodMiniString<string>;
|
|
53
|
-
code_verifier: z.ZodMiniString<string>;
|
|
54
|
-
}, z.core.$strip>;
|
|
55
|
-
|
|
56
|
-
export declare type ExchangeCodeResponse = z.infer<typeof ExchangeCodeResponseSchema>;
|
|
108
|
+
export declare type ExchangeCodeResponse = TokenResponse;
|
|
57
109
|
|
|
58
110
|
export declare const ExchangeCodeResponseSchema: z.ZodMiniObject<{
|
|
59
111
|
access_token: z.ZodMiniString<string>;
|
|
112
|
+
token_type: z.ZodMiniString<string>;
|
|
113
|
+
expires_in: z.ZodMiniNumber<number>;
|
|
114
|
+
id_token: z.ZodMiniString<string>;
|
|
115
|
+
refresh_token: z.ZodMiniString<string>;
|
|
60
116
|
}, z.core.$strip>;
|
|
61
117
|
|
|
62
118
|
export declare interface JWTHeader {
|
|
63
119
|
alg: string;
|
|
64
120
|
typ: string;
|
|
121
|
+
kid?: string;
|
|
65
122
|
}
|
|
66
123
|
|
|
67
124
|
export declare type PollRequest = z.infer<typeof PollRequestSchema>;
|
|
68
125
|
|
|
69
126
|
/**
|
|
70
127
|
* Poll request/response schema
|
|
128
|
+
* POST /oauth/poll
|
|
71
129
|
*/
|
|
72
130
|
export declare const PollRequestSchema: z.ZodMiniObject<{
|
|
73
131
|
polling_code: z.ZodMiniString<string>;
|
|
@@ -88,28 +146,41 @@ export declare const PollResponseSchema: z.ZodMiniObject<{
|
|
|
88
146
|
export declare type TokenInfo = z.infer<typeof TokenInfoSchema>;
|
|
89
147
|
|
|
90
148
|
/**
|
|
91
|
-
* Token info schema
|
|
149
|
+
* Token info schema (parsed from JWT)
|
|
150
|
+
* Standard OIDC claims
|
|
92
151
|
*/
|
|
93
152
|
export declare const TokenInfoSchema: z.ZodMiniObject<{
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
153
|
+
iss: z.ZodMiniString<string>;
|
|
154
|
+
sub: z.ZodMiniString<string>;
|
|
155
|
+
aud: z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>;
|
|
156
|
+
exp: z.ZodMiniNumber<number>;
|
|
157
|
+
iat: z.ZodMiniNumber<number>;
|
|
158
|
+
nonce: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
159
|
+
auth_time: z.ZodMiniOptional<z.ZodMiniNumber<number>>;
|
|
97
160
|
}, z.core.$strip>;
|
|
98
161
|
|
|
99
|
-
export declare type
|
|
162
|
+
export declare type TokenResponse = z.infer<typeof TokenResponseSchema>;
|
|
100
163
|
|
|
101
164
|
/**
|
|
102
|
-
*
|
|
165
|
+
* Token exchange response schema (OAuth2 standard)
|
|
166
|
+
* POST /oauth/token
|
|
103
167
|
*/
|
|
104
|
-
export declare const
|
|
168
|
+
export declare const TokenResponseSchema: z.ZodMiniObject<{
|
|
105
169
|
access_token: z.ZodMiniString<string>;
|
|
170
|
+
token_type: z.ZodMiniString<string>;
|
|
171
|
+
expires_in: z.ZodMiniNumber<number>;
|
|
172
|
+
id_token: z.ZodMiniString<string>;
|
|
173
|
+
refresh_token: z.ZodMiniString<string>;
|
|
106
174
|
}, z.core.$strip>;
|
|
107
175
|
|
|
108
|
-
export declare type
|
|
176
|
+
export declare type UserInfoResponse = z.infer<typeof UserInfoResponseSchema>;
|
|
109
177
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
178
|
+
/**
|
|
179
|
+
* UserInfo response schema
|
|
180
|
+
* GET /oauth/userinfo
|
|
181
|
+
*/
|
|
182
|
+
export declare const UserInfoResponseSchema: z.ZodMiniObject<{
|
|
183
|
+
sub: z.ZodMiniString<string>;
|
|
113
184
|
}, z.core.$strip>;
|
|
114
185
|
|
|
115
186
|
export { }
|
package/dist/index.esm.js
CHANGED
|
@@ -1,225 +1,354 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
1
|
+
var h = (u, e, r) => new Promise((o, s) => {
|
|
2
|
+
var a = (l) => {
|
|
3
3
|
try {
|
|
4
|
-
|
|
5
|
-
} catch (
|
|
6
|
-
|
|
4
|
+
c(r.next(l));
|
|
5
|
+
} catch (m) {
|
|
6
|
+
s(m);
|
|
7
7
|
}
|
|
8
|
-
},
|
|
8
|
+
}, n = (l) => {
|
|
9
9
|
try {
|
|
10
|
-
|
|
11
|
-
} catch (
|
|
12
|
-
|
|
10
|
+
c(r.throw(l));
|
|
11
|
+
} catch (m) {
|
|
12
|
+
s(m);
|
|
13
13
|
}
|
|
14
|
-
},
|
|
15
|
-
|
|
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
|
-
import { z as
|
|
18
|
-
import { sha256 as
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
polling_code:
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}),
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}),
|
|
35
|
-
|
|
36
|
-
}), j =
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
return btoa(a).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
17
|
+
import { z as t } from "zod/v4-mini";
|
|
18
|
+
import { sha256 as y } from "js-sha256";
|
|
19
|
+
const T = t.object({
|
|
20
|
+
deep_link: t.string(),
|
|
21
|
+
polling_code: t.string(),
|
|
22
|
+
expired_at: t.number()
|
|
23
|
+
}), b = t.object({
|
|
24
|
+
polling_code: t.string()
|
|
25
|
+
}), A = ["pending", "authorized", "rejected", "expired"], I = t.enum(A), R = t.object({
|
|
26
|
+
status: I,
|
|
27
|
+
authorization_code: t.optional(t.string())
|
|
28
|
+
}), k = t.object({
|
|
29
|
+
access_token: t.string(),
|
|
30
|
+
token_type: t.string(),
|
|
31
|
+
expires_in: t.number(),
|
|
32
|
+
id_token: t.string(),
|
|
33
|
+
refresh_token: t.string()
|
|
34
|
+
}), x = t.object({
|
|
35
|
+
sub: t.string()
|
|
36
|
+
}), j = t.object({
|
|
37
|
+
iss: t.string(),
|
|
38
|
+
sub: t.string(),
|
|
39
|
+
aud: t.union([t.string(), t.array(t.string())]),
|
|
40
|
+
exp: t.number(),
|
|
41
|
+
iat: t.number(),
|
|
42
|
+
nonce: t.optional(t.string()),
|
|
43
|
+
auth_time: t.optional(t.number())
|
|
44
|
+
}), z = k;
|
|
45
|
+
function w(u) {
|
|
46
|
+
return btoa(u).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
48
47
|
}
|
|
49
|
-
function u
|
|
50
|
-
let
|
|
51
|
-
for (;
|
|
52
|
-
|
|
53
|
-
return atob(
|
|
48
|
+
function _(u) {
|
|
49
|
+
let e = u.replace(/-/g, "+").replace(/_/g, "/");
|
|
50
|
+
for (; e.length % 4; )
|
|
51
|
+
e += "=";
|
|
52
|
+
return atob(e);
|
|
54
53
|
}
|
|
55
|
-
const
|
|
56
|
-
ssoBaseUrl:
|
|
57
|
-
providerAddress:
|
|
58
|
-
pollingInterval:
|
|
59
|
-
})
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
this.config = O.parse(o), this.ssoBaseUrl = this.config.ssoBaseUrl || T, this.providerAddress = this.config.providerAddress, this.pollingInterval = this.config.pollingInterval || C;
|
|
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
|
+
ssoBaseUrl: t.url(),
|
|
56
|
+
providerAddress: t.string(),
|
|
57
|
+
pollingInterval: t.optional(t.number())
|
|
58
|
+
}), d = class d {
|
|
59
|
+
constructor(e) {
|
|
60
|
+
this.config = U.parse(e), this.ssoBaseUrl = this.config.ssoBaseUrl || E, this.providerAddress = this.config.providerAddress, this.pollingInterval = this.config.pollingInterval || v;
|
|
63
61
|
}
|
|
64
|
-
generateCodeVerifier(
|
|
65
|
-
let
|
|
66
|
-
const
|
|
67
|
-
if (
|
|
68
|
-
|
|
62
|
+
generateCodeVerifier(e = 128) {
|
|
63
|
+
let r;
|
|
64
|
+
const o = typeof window != "undefined" && window.crypto;
|
|
65
|
+
if (o && o.getRandomValues)
|
|
66
|
+
r = new Uint8Array(e), o.getRandomValues(r);
|
|
69
67
|
else {
|
|
70
|
-
|
|
71
|
-
for (let
|
|
72
|
-
|
|
68
|
+
r = new Uint8Array(e);
|
|
69
|
+
for (let a = 0; a < e; a++)
|
|
70
|
+
r[a] = Math.floor(Math.random() * 256);
|
|
73
71
|
}
|
|
74
|
-
let
|
|
75
|
-
for (let
|
|
76
|
-
|
|
77
|
-
return
|
|
72
|
+
let s = "";
|
|
73
|
+
for (let a = 0; a < r.length; a++)
|
|
74
|
+
s += String.fromCharCode(r[a]);
|
|
75
|
+
return w(s);
|
|
78
76
|
}
|
|
79
|
-
generateCodeChallenge(
|
|
80
|
-
|
|
77
|
+
generateCodeChallenge(e) {
|
|
78
|
+
const r = y.array(e), o = String.fromCharCode(...r);
|
|
79
|
+
return w(o);
|
|
81
80
|
}
|
|
81
|
+
/**
|
|
82
|
+
* Initiates OAuth2 authorization flow with response_mode=json for SPA
|
|
83
|
+
* GET /oauth/authorize?response_type=code&response_mode=json&...
|
|
84
|
+
*/
|
|
82
85
|
generateDeeplink() {
|
|
83
|
-
return
|
|
84
|
-
const
|
|
85
|
-
sessionStorage.setItem(
|
|
86
|
-
const
|
|
87
|
-
|
|
86
|
+
return h(this, null, function* () {
|
|
87
|
+
const e = this.generateCodeVerifier(), r = this.generateCodeChallenge(e);
|
|
88
|
+
sessionStorage.setItem(i + "code_verifier", e);
|
|
89
|
+
const o = new URLSearchParams({
|
|
90
|
+
response_type: "code",
|
|
91
|
+
response_mode: "json",
|
|
92
|
+
client_id: this.providerAddress,
|
|
93
|
+
scope: "openid",
|
|
94
|
+
code_challenge: r,
|
|
88
95
|
code_challenge_method: "S256"
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
})).json();
|
|
99
|
-
return S.parse(c);
|
|
96
|
+
}), s = `${this.config.ssoBaseUrl}/oauth/authorize?${o.toString()}`, a = yield fetch(s, {
|
|
97
|
+
method: "GET"
|
|
98
|
+
});
|
|
99
|
+
if (!a.ok) {
|
|
100
|
+
const c = yield a.json().catch(() => ({ error: a.statusText }));
|
|
101
|
+
throw new Error(`Authorize failed: ${c.error_description || c.error || a.statusText}`);
|
|
102
|
+
}
|
|
103
|
+
const n = yield a.json();
|
|
104
|
+
return T.parse(n);
|
|
100
105
|
});
|
|
101
106
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
107
|
+
/**
|
|
108
|
+
* Polls for authorization completion
|
|
109
|
+
* POST /oauth/poll
|
|
110
|
+
*/
|
|
111
|
+
pollAuth(e) {
|
|
112
|
+
return h(this, null, function* () {
|
|
113
|
+
const r = {
|
|
114
|
+
polling_code: e
|
|
106
115
|
};
|
|
107
|
-
|
|
108
|
-
const
|
|
116
|
+
b.parse(r);
|
|
117
|
+
const o = yield fetch(f(this.config.ssoBaseUrl, "/oauth/poll"), {
|
|
109
118
|
method: "POST",
|
|
110
119
|
headers: {
|
|
111
|
-
"Content-Type": "application/json"
|
|
112
|
-
"X-PROVIDER-ADDRESS": this.providerAddress
|
|
120
|
+
"Content-Type": "application/json"
|
|
113
121
|
},
|
|
114
|
-
body: JSON.stringify(
|
|
122
|
+
body: JSON.stringify(r)
|
|
115
123
|
});
|
|
116
|
-
if (!
|
|
117
|
-
throw new Error(`Poll failed: ${
|
|
118
|
-
const
|
|
119
|
-
return
|
|
124
|
+
if (!o.ok)
|
|
125
|
+
throw new Error(`Poll failed: ${o.statusText}`);
|
|
126
|
+
const s = yield o.json();
|
|
127
|
+
return R.parse(s);
|
|
120
128
|
});
|
|
121
129
|
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
const
|
|
132
|
-
|
|
130
|
+
/**
|
|
131
|
+
* Exchanges authorization code for tokens
|
|
132
|
+
* POST /oauth/token (application/x-www-form-urlencoded)
|
|
133
|
+
* Returns both access_token and id_token
|
|
134
|
+
*/
|
|
135
|
+
exchangeToken(e) {
|
|
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({
|
|
140
|
+
grant_type: "authorization_code",
|
|
141
|
+
code: e,
|
|
142
|
+
client_id: this.providerAddress,
|
|
143
|
+
code_verifier: r
|
|
144
|
+
}), s = yield fetch(
|
|
145
|
+
f(this.config.ssoBaseUrl, "/oauth/token"),
|
|
133
146
|
{
|
|
134
147
|
method: "POST",
|
|
135
148
|
headers: {
|
|
136
|
-
"Content-Type": "application/
|
|
137
|
-
"X-PROVIDER-ADDRESS": this.providerAddress
|
|
149
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
138
150
|
},
|
|
139
|
-
body:
|
|
151
|
+
body: o.toString()
|
|
140
152
|
}
|
|
141
153
|
);
|
|
142
|
-
if (!
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
throw new Error("Exchange failed");
|
|
154
|
+
if (!s.ok) {
|
|
155
|
+
const l = yield s.json().catch(() => ({ error: s.statusText }));
|
|
156
|
+
throw new Error(`Token exchange failed: ${l.error_description || l.error || s.statusText}`);
|
|
157
|
+
}
|
|
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);
|
|
160
|
+
const c = Date.now() + n.expires_in * 1e3;
|
|
161
|
+
return localStorage.setItem(p, c.toString()), sessionStorage.removeItem(i + "code_verifier"), n;
|
|
151
162
|
});
|
|
152
163
|
}
|
|
164
|
+
/**
|
|
165
|
+
* Verifies authentication by calling userinfo endpoint
|
|
166
|
+
* GET /oauth/userinfo
|
|
167
|
+
* Automatically refreshes token on 401 if refresh token is available
|
|
168
|
+
*/
|
|
153
169
|
verifyAuth() {
|
|
154
|
-
return
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
170
|
+
return h(this, null, function* () {
|
|
171
|
+
return this.withAutoRefresh(() => h(this, null, function* () {
|
|
172
|
+
const e = this.getAccessToken();
|
|
173
|
+
if (!e)
|
|
174
|
+
return null;
|
|
175
|
+
const r = yield fetch(
|
|
176
|
+
f(this.config.ssoBaseUrl, "/oauth/userinfo"),
|
|
177
|
+
{
|
|
178
|
+
method: "GET",
|
|
179
|
+
headers: {
|
|
180
|
+
Authorization: `Bearer ${e}`
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
);
|
|
184
|
+
if (!r.ok) {
|
|
185
|
+
if (r.status === 401) {
|
|
186
|
+
const s = new Error("Unauthorized");
|
|
187
|
+
throw s.response = { status: 401 }, s;
|
|
188
|
+
}
|
|
189
|
+
return null;
|
|
171
190
|
}
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
const r = yield n.json(), t = v.parse(r);
|
|
176
|
-
return t.access_token && localStorage.setItem(
|
|
177
|
-
l + "access_token",
|
|
178
|
-
t.access_token
|
|
179
|
-
), t.is_valid;
|
|
191
|
+
const o = yield r.json();
|
|
192
|
+
return x.parse(o);
|
|
193
|
+
}));
|
|
180
194
|
});
|
|
181
195
|
}
|
|
196
|
+
/**
|
|
197
|
+
* Gets stored access token
|
|
198
|
+
*/
|
|
182
199
|
getAccessToken() {
|
|
183
|
-
return localStorage.getItem(
|
|
200
|
+
return localStorage.getItem(i + "access_token");
|
|
184
201
|
}
|
|
202
|
+
/**
|
|
203
|
+
* Gets stored ID token
|
|
204
|
+
*/
|
|
205
|
+
getIdToken() {
|
|
206
|
+
return localStorage.getItem(i + "id_token");
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Decodes and validates JWT token to extract claims
|
|
210
|
+
* Works with both access_token and id_token (EdDSA signed)
|
|
211
|
+
*/
|
|
185
212
|
getAuthData() {
|
|
186
|
-
const
|
|
187
|
-
if (!
|
|
188
|
-
const
|
|
189
|
-
if (
|
|
213
|
+
const e = this.getIdToken() || this.getAccessToken();
|
|
214
|
+
if (!e) return null;
|
|
215
|
+
const r = e.split(".");
|
|
216
|
+
if (r.length !== 3)
|
|
190
217
|
return null;
|
|
191
|
-
let
|
|
218
|
+
let o;
|
|
192
219
|
try {
|
|
193
|
-
const
|
|
194
|
-
|
|
195
|
-
} catch (
|
|
220
|
+
const n = _(r[0]);
|
|
221
|
+
o = JSON.parse(n);
|
|
222
|
+
} catch (n) {
|
|
196
223
|
return null;
|
|
197
224
|
}
|
|
198
|
-
if (
|
|
225
|
+
if (o.alg !== "RS256" || o.typ !== "JWT")
|
|
199
226
|
return null;
|
|
200
|
-
let
|
|
227
|
+
let s;
|
|
201
228
|
try {
|
|
202
|
-
const
|
|
203
|
-
|
|
204
|
-
} catch (
|
|
229
|
+
const n = JSON.parse(_(r[1]));
|
|
230
|
+
s = j.parse(n);
|
|
231
|
+
} catch (n) {
|
|
205
232
|
return null;
|
|
206
233
|
}
|
|
207
|
-
return
|
|
234
|
+
return (Array.isArray(s.aud) ? s.aud : [s.aud]).includes(this.providerAddress) ? s : null;
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Gets the subject (user identifier) from the token
|
|
238
|
+
*/
|
|
239
|
+
getSubject() {
|
|
240
|
+
const e = this.getAuthData();
|
|
241
|
+
return (e == null ? void 0 : e.sub) || null;
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Checks if the current token is expired
|
|
245
|
+
*/
|
|
246
|
+
isTokenExpired() {
|
|
247
|
+
const e = this.getAuthData();
|
|
248
|
+
return e ? Date.now() / 1e3 > e.exp : !0;
|
|
208
249
|
}
|
|
250
|
+
/**
|
|
251
|
+
* Clears all stored authentication data
|
|
252
|
+
*/
|
|
209
253
|
logout() {
|
|
210
|
-
localStorage.removeItem(
|
|
254
|
+
localStorage.removeItem(i + "access_token"), localStorage.removeItem(i + "id_token"), localStorage.removeItem(g), localStorage.removeItem(p), sessionStorage.removeItem(i + "code_verifier");
|
|
211
255
|
}
|
|
212
|
-
|
|
256
|
+
/**
|
|
257
|
+
* Gets stored refresh token
|
|
258
|
+
*/
|
|
259
|
+
getRefreshToken() {
|
|
260
|
+
return localStorage.getItem(g);
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Checks if a refresh token is available
|
|
264
|
+
*/
|
|
265
|
+
hasRefreshToken() {
|
|
266
|
+
return !!this.getRefreshToken();
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Checks if the access token is expired or will expire soon (within 5 minutes)
|
|
270
|
+
*/
|
|
271
|
+
isAccessTokenExpired() {
|
|
272
|
+
const e = localStorage.getItem(p);
|
|
273
|
+
if (!e) return !0;
|
|
274
|
+
const r = parseInt(e, 10), o = Date.now(), s = 300 * 1e3;
|
|
275
|
+
return o >= r - s;
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Refreshes the access token using the stored refresh token
|
|
279
|
+
* POST /oauth/token with grant_type=refresh_token
|
|
280
|
+
* Uses singleton pattern to prevent concurrent refresh requests (race condition)
|
|
281
|
+
*/
|
|
282
|
+
refreshAccessToken() {
|
|
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* () {
|
|
294
|
+
const e = this.getRefreshToken();
|
|
295
|
+
if (!e)
|
|
296
|
+
throw new Error("No refresh token available");
|
|
297
|
+
const r = new URLSearchParams({
|
|
298
|
+
grant_type: "refresh_token",
|
|
299
|
+
refresh_token: e,
|
|
300
|
+
client_id: this.providerAddress
|
|
301
|
+
}), o = yield fetch(
|
|
302
|
+
f(this.config.ssoBaseUrl, "/oauth/token"),
|
|
303
|
+
{
|
|
304
|
+
method: "POST",
|
|
305
|
+
headers: {
|
|
306
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
307
|
+
},
|
|
308
|
+
body: r.toString()
|
|
309
|
+
}
|
|
310
|
+
);
|
|
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}`);
|
|
314
|
+
}
|
|
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);
|
|
317
|
+
const n = Date.now() + a.expires_in * 1e3;
|
|
318
|
+
return localStorage.setItem(p, n.toString()), a;
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Executes a function that makes an authenticated request
|
|
323
|
+
* Automatically refreshes token and retries on 401 error
|
|
324
|
+
*/
|
|
325
|
+
withAutoRefresh(e, r = 1) {
|
|
326
|
+
return h(this, null, function* () {
|
|
327
|
+
var o, s, a;
|
|
328
|
+
try {
|
|
329
|
+
return yield e();
|
|
330
|
+
} catch (n) {
|
|
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())
|
|
332
|
+
try {
|
|
333
|
+
return yield this.refreshAccessToken(), yield e();
|
|
334
|
+
} catch (l) {
|
|
335
|
+
throw n;
|
|
336
|
+
}
|
|
337
|
+
throw n;
|
|
338
|
+
}
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
};
|
|
342
|
+
d.refreshPromise = null;
|
|
343
|
+
let S = d;
|
|
213
344
|
export {
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
j as VerifyTokenRequestSchema,
|
|
224
|
-
v as VerifyTokenResponseSchema
|
|
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
|
|
225
354
|
};
|
package/dist/index.umd.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(t
|
|
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"})}));
|