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