@fjordid/client 0.1.0

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 ADDED
@@ -0,0 +1,158 @@
1
+ # @fjordid/client
2
+
3
+ Lightweight JavaScript/TypeScript client for [FjordID](https://fjordid.eu) authentication. Wraps Keycloak OIDC with a simple, developer-friendly API.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @fjordid/client
9
+ # or
10
+ pnpm add @fjordid/client
11
+ ```
12
+
13
+ ## Quick Start
14
+
15
+ ```typescript
16
+ import { FjordAuth } from "@fjordid/client";
17
+
18
+ const auth = new FjordAuth({
19
+ domain: "your-app.fjordid.eu",
20
+ clientId: "your-client-id",
21
+ });
22
+
23
+ await auth.init();
24
+ auth.login();
25
+ ```
26
+
27
+ ## Usage
28
+
29
+ ### Initialize
30
+
31
+ ```typescript
32
+ const auth = new FjordAuth({
33
+ domain: "your-app.fjordid.eu",
34
+ clientId: "your-client-id",
35
+ // Optional overrides:
36
+ // authUrl: 'https://auth.fjordid.eu',
37
+ // realm: 'fjordid',
38
+ // redirectUri: window.location.origin,
39
+ // silentSso: true,
40
+ // initTimeout: 10000,
41
+ });
42
+
43
+ const isLoggedIn = await auth.init();
44
+ ```
45
+
46
+ ### Login / Register / Logout
47
+
48
+ ```typescript
49
+ auth.login(); // Redirect to login page
50
+ auth.register(); // Redirect to registration page
51
+ auth.logout(); // Log out and redirect home
52
+
53
+ // Custom redirect after login
54
+ auth.login("/dashboard");
55
+ ```
56
+
57
+ ### User Info
58
+
59
+ ```typescript
60
+ if (auth.authenticated) {
61
+ console.log(auth.user?.email);
62
+ console.log(auth.user?.name);
63
+ console.log(auth.user?.id);
64
+ }
65
+ ```
66
+
67
+ ### Access Tokens
68
+
69
+ ```typescript
70
+ // Get a valid token (auto-refreshes if expiring soon)
71
+ const token = await auth.getToken();
72
+
73
+ // Use in API calls
74
+ const res = await fetch("/api/data", {
75
+ headers: { Authorization: `Bearer ${token}` },
76
+ });
77
+ ```
78
+
79
+ ### Events
80
+
81
+ ```typescript
82
+ const unsub = auth.on("onAuthSuccess", () => {
83
+ console.log("Logged in:", auth.user?.email);
84
+ });
85
+
86
+ auth.on("onAuthLogout", () => {
87
+ console.log("Logged out");
88
+ });
89
+
90
+ // Unsubscribe
91
+ unsub();
92
+ ```
93
+
94
+ ## API Reference
95
+
96
+ ### `new FjordAuth(options)`
97
+
98
+ | Option | Type | Default | Description |
99
+ | ----------------------- | --------- | ------------------------- | -------------------------------- |
100
+ | `domain` | `string` | **required** | Your FjordID domain |
101
+ | `clientId` | `string` | **required** | OIDC client ID |
102
+ | `authUrl` | `string` | `https://auth.fjordid.eu` | Keycloak server URL |
103
+ | `realm` | `string` | `fjordid` | Keycloak realm |
104
+ | `redirectUri` | `string` | `window.location.origin` | Post-login redirect |
105
+ | `postLogoutRedirectUri` | `string` | `window.location.origin` | Post-logout redirect |
106
+ | `silentSso` | `boolean` | `true` | Enable silent SSO check |
107
+ | `initTimeout` | `number` | `10000` | Init timeout (ms) |
108
+ | `tokenRefreshBuffer` | `number` | `30` | Seconds before expiry to refresh |
109
+
110
+ ### Properties
111
+
112
+ | Property | Type | Description |
113
+ | --------------- | --------------------- | ----------------------------- |
114
+ | `authenticated` | `boolean` | Whether the user is logged in |
115
+ | `user` | `FjordUser \| null` | Current user profile |
116
+ | `token` | `string \| undefined` | Raw access token |
117
+ | `idToken` | `string \| undefined` | Raw ID token |
118
+
119
+ ### Methods
120
+
121
+ | Method | Returns | Description |
122
+ | ------------------------ | ------------------------------ | --------------------------- |
123
+ | `init()` | `Promise<boolean>` | Initialize auth (call once) |
124
+ | `login(redirectUri?)` | `void` | Redirect to login |
125
+ | `register(redirectUri?)` | `void` | Redirect to registration |
126
+ | `logout(redirectUri?)` | `void` | Log out |
127
+ | `getToken()` | `Promise<string \| undefined>` | Get valid access token |
128
+ | `refreshToken()` | `Promise<string \| undefined>` | Force token refresh |
129
+ | `on(event, callback)` | `() => void` | Subscribe to events |
130
+
131
+ ### Events
132
+
133
+ | Event | When |
134
+ | ---------------- | -------------------------------- |
135
+ | `onReady` | Keycloak adapter ready |
136
+ | `onAuthSuccess` | Login succeeded |
137
+ | `onAuthLogout` | User logged out |
138
+ | `onAuthError` | Auth error occurred |
139
+ | `onTokenExpired` | Token expired and refresh failed |
140
+
141
+ ## Silent SSO
142
+
143
+ For silent SSO to work, serve this HTML file at `/silent-check-sso.html`:
144
+
145
+ ```html
146
+ <!doctype html>
147
+ <html>
148
+ <body>
149
+ <script>
150
+ parent.postMessage(location.href, location.origin);
151
+ </script>
152
+ </body>
153
+ </html>
154
+ ```
155
+
156
+ ## License
157
+
158
+ MIT
@@ -0,0 +1,90 @@
1
+ import type { FjordAuthOptions, FjordUser, FjordAuthEvent, FjordAuthEventCallback } from "./types.js";
2
+ /**
3
+ * FjordAuth — a lightweight, developer-friendly wrapper around Keycloak OIDC.
4
+ *
5
+ * @example
6
+ * ```ts
7
+ * import { FjordAuth } from '@fjordid/client';
8
+ *
9
+ * const auth = new FjordAuth({
10
+ * domain: 'your-app.fjordid.eu',
11
+ * clientId: 'your-client-id',
12
+ * });
13
+ *
14
+ * await auth.init();
15
+ * auth.login();
16
+ * ```
17
+ */
18
+ export declare class FjordAuth {
19
+ private readonly kc;
20
+ private readonly options;
21
+ private initialized;
22
+ private initPromise;
23
+ private listeners;
24
+ /** The currently authenticated user, or `null` if not logged in. */
25
+ user: FjordUser | null;
26
+ constructor(options: FjordAuthOptions);
27
+ /**
28
+ * Initialize authentication. Performs a silent SSO check to see if the user
29
+ * is already logged in.
30
+ *
31
+ * @returns `true` if the user is authenticated, `false` otherwise.
32
+ */
33
+ init(): Promise<boolean>;
34
+ private doInit;
35
+ /** Whether the user is currently authenticated. */
36
+ get authenticated(): boolean;
37
+ /**
38
+ * Redirect to the FjordID login page.
39
+ *
40
+ * @param redirectUri — Override the post-login redirect. Defaults to `options.redirectUri`.
41
+ */
42
+ login(redirectUri?: string): void;
43
+ /**
44
+ * Redirect to the FjordID registration page.
45
+ *
46
+ * @param redirectUri — Override the post-registration redirect.
47
+ */
48
+ register(redirectUri?: string): void;
49
+ /**
50
+ * Log out and redirect to the post-logout URL.
51
+ *
52
+ * @param redirectUri — Override the post-logout redirect.
53
+ */
54
+ logout(redirectUri?: string): void;
55
+ /**
56
+ * Get a valid access token, refreshing if needed.
57
+ *
58
+ * @returns The access token string, or `undefined` if not authenticated.
59
+ */
60
+ getToken(): Promise<string | undefined>;
61
+ /**
62
+ * Force-refresh the access token.
63
+ *
64
+ * @returns The new access token string, or `undefined` on failure.
65
+ */
66
+ refreshToken(): Promise<string | undefined>;
67
+ /** The raw access token, or `undefined`. */
68
+ get token(): string | undefined;
69
+ /** The raw ID token, or `undefined`. */
70
+ get idToken(): string | undefined;
71
+ /**
72
+ * Subscribe to an auth event.
73
+ *
74
+ * @returns An unsubscribe function.
75
+ */
76
+ on(event: FjordAuthEvent, callback: FjordAuthEventCallback): () => void;
77
+ private emit;
78
+ private syncUser;
79
+ /**
80
+ * Validate that a redirect URI is a real URL and not an "undefined" string
81
+ * produced by an unset environment variable.
82
+ */
83
+ private assertValidRedirectUri;
84
+ /**
85
+ * Keycloak may lose authServerUrl after an init timeout.
86
+ * Ensure it's always set correctly before building redirect URLs.
87
+ */
88
+ private ensureAuthServerUrl;
89
+ }
90
+ //# sourceMappingURL=FjordAuth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FjordAuth.d.ts","sourceRoot":"","sources":["../src/FjordAuth.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,gBAAgB,EAChB,SAAS,EACT,cAAc,EACd,sBAAsB,EACvB,MAAM,YAAY,CAAC;AAOpB;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAW;IAC9B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAYL;IAEnB,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,WAAW,CAAiC;IACpD,OAAO,CAAC,SAAS,CAA0D;IAE3E,oEAAoE;IACpE,IAAI,EAAE,SAAS,GAAG,IAAI,CAAQ;gBAElB,OAAO,EAAE,gBAAgB;IA6DrC;;;;;OAKG;IACG,IAAI,IAAI,OAAO,CAAC,OAAO,CAAC;YAahB,MAAM;IA0DpB,mDAAmD;IACnD,IAAI,aAAa,IAAI,OAAO,CAE3B;IAED;;;;OAIG;IACH,KAAK,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI;IAOjC;;;;OAIG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI;IAOpC;;;;OAIG;IACH,MAAM,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI;IAWlC;;;;OAIG;IACG,QAAQ,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAU7C;;;;OAIG;IACG,YAAY,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAWjD,4CAA4C;IAC5C,IAAI,KAAK,IAAI,MAAM,GAAG,SAAS,CAE9B;IAED,wCAAwC;IACxC,IAAI,OAAO,IAAI,MAAM,GAAG,SAAS,CAEhC;IAMD;;;;OAIG;IACH,EAAE,CAAC,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAE,sBAAsB,GAAG,MAAM,IAAI;IAQvE,OAAO,CAAC,IAAI;IAcZ,OAAO,CAAC,QAAQ;IA2BhB;;;OAGG;IACH,OAAO,CAAC,sBAAsB;IAe9B;;;OAGG;IACH,OAAO,CAAC,mBAAmB;CAS5B"}
@@ -0,0 +1,295 @@
1
+ import Keycloak from "keycloak-js";
2
+ const DEFAULT_AUTH_URL = "https://auth.fjordid.eu";
3
+ const DEFAULT_REALM = "fjordid";
4
+ const DEFAULT_INIT_TIMEOUT = 10_000;
5
+ const DEFAULT_TOKEN_REFRESH_BUFFER = 30;
6
+ /**
7
+ * FjordAuth — a lightweight, developer-friendly wrapper around Keycloak OIDC.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * import { FjordAuth } from '@fjordid/client';
12
+ *
13
+ * const auth = new FjordAuth({
14
+ * domain: 'your-app.fjordid.eu',
15
+ * clientId: 'your-client-id',
16
+ * });
17
+ *
18
+ * await auth.init();
19
+ * auth.login();
20
+ * ```
21
+ */
22
+ export class FjordAuth {
23
+ kc;
24
+ options;
25
+ initialized = false;
26
+ initPromise = null;
27
+ listeners = new Map();
28
+ /** The currently authenticated user, or `null` if not logged in. */
29
+ user = null;
30
+ constructor(options) {
31
+ // Validate required config up-front so developers get a clear error
32
+ // instead of Keycloak's generic "Page not found".
33
+ if (!options.clientId || options.clientId.trim() === "") {
34
+ throw new Error("[FjordAuth] Missing clientId. " +
35
+ "Make sure you pass a valid clientId when creating FjordAuth. " +
36
+ "If you are reading it from an environment variable, " +
37
+ "ensure the variable is set before the app starts.");
38
+ }
39
+ this.options = {
40
+ ...options,
41
+ authUrl: options.authUrl ?? DEFAULT_AUTH_URL,
42
+ realm: options.realm ?? DEFAULT_REALM,
43
+ redirectUri: options.redirectUri ??
44
+ (typeof window !== "undefined" ? window.location.origin : ""),
45
+ postLogoutRedirectUri: options.postLogoutRedirectUri ??
46
+ (typeof window !== "undefined" ? window.location.origin : ""),
47
+ silentSso: options.silentSso ?? true,
48
+ initTimeout: options.initTimeout ?? DEFAULT_INIT_TIMEOUT,
49
+ tokenRefreshBuffer: options.tokenRefreshBuffer ?? DEFAULT_TOKEN_REFRESH_BUFFER,
50
+ };
51
+ // Validate redirectUri after defaults are applied
52
+ this.assertValidRedirectUri(this.options.redirectUri, "redirectUri");
53
+ this.assertValidRedirectUri(this.options.postLogoutRedirectUri, "postLogoutRedirectUri");
54
+ this.kc = new Keycloak({
55
+ url: this.options.authUrl,
56
+ realm: this.options.realm,
57
+ clientId: this.options.clientId,
58
+ });
59
+ // Wire up Keycloak events
60
+ this.kc.onReady = () => this.emit("onReady");
61
+ this.kc.onAuthSuccess = () => {
62
+ this.syncUser();
63
+ this.emit("onAuthSuccess");
64
+ };
65
+ this.kc.onAuthLogout = () => {
66
+ this.user = null;
67
+ this.emit("onAuthLogout");
68
+ };
69
+ this.kc.onAuthError = () => this.emit("onAuthError");
70
+ this.kc.onTokenExpired = () => {
71
+ this.refreshToken().catch(() => this.emit("onTokenExpired"));
72
+ };
73
+ }
74
+ // ---------------------------------------------------------------------------
75
+ // Lifecycle
76
+ // ---------------------------------------------------------------------------
77
+ /**
78
+ * Initialize authentication. Performs a silent SSO check to see if the user
79
+ * is already logged in.
80
+ *
81
+ * @returns `true` if the user is authenticated, `false` otherwise.
82
+ */
83
+ async init() {
84
+ if (this.initialized) {
85
+ return this.authenticated;
86
+ }
87
+ if (this.initPromise) {
88
+ return this.initPromise;
89
+ }
90
+ this.initPromise = this.doInit();
91
+ return this.initPromise;
92
+ }
93
+ async doInit() {
94
+ try {
95
+ const authenticated = await withTimeout(this.kc.init({
96
+ onLoad: "check-sso",
97
+ pkceMethod: "S256",
98
+ checkLoginIframe: false,
99
+ silentCheckSsoRedirectUri: this.options.silentSso
100
+ ? window.location.origin + "/silent-check-sso.html"
101
+ : undefined,
102
+ }), this.options.initTimeout, "FjordAuth init timeout — SSO check took too long");
103
+ this.initialized = true;
104
+ if (authenticated) {
105
+ this.syncUser();
106
+ }
107
+ return authenticated;
108
+ }
109
+ catch (error) {
110
+ const msg = error instanceof Error ? error.message : String(error);
111
+ // Keycloak double-init guard
112
+ if (msg.includes("can only be initialized once")) {
113
+ this.initialized = true;
114
+ this.syncUser();
115
+ return this.authenticated;
116
+ }
117
+ // Timeout / 3rd-party cookie issues — degrade gracefully
118
+ const isRecoverable = msg.toLowerCase().includes("timeout") ||
119
+ msg.includes("3rd party") ||
120
+ msg.includes("third party") ||
121
+ msg.includes("iframe");
122
+ if (isRecoverable) {
123
+ console.warn("[FjordAuth] SSO check failed (3rd-party cookies likely blocked), proceeding without SSO:", msg);
124
+ this.initialized = true;
125
+ return false;
126
+ }
127
+ console.error("[FjordAuth] Initialization failed:", error);
128
+ this.initialized = true;
129
+ return false;
130
+ }
131
+ }
132
+ // ---------------------------------------------------------------------------
133
+ // Auth actions
134
+ // ---------------------------------------------------------------------------
135
+ /** Whether the user is currently authenticated. */
136
+ get authenticated() {
137
+ return this.kc.authenticated ?? false;
138
+ }
139
+ /**
140
+ * Redirect to the FjordID login page.
141
+ *
142
+ * @param redirectUri — Override the post-login redirect. Defaults to `options.redirectUri`.
143
+ */
144
+ login(redirectUri) {
145
+ const uri = redirectUri ?? this.options.redirectUri;
146
+ this.assertValidRedirectUri(uri, "redirectUri");
147
+ this.ensureAuthServerUrl();
148
+ this.kc.login({ redirectUri: uri });
149
+ }
150
+ /**
151
+ * Redirect to the FjordID registration page.
152
+ *
153
+ * @param redirectUri — Override the post-registration redirect.
154
+ */
155
+ register(redirectUri) {
156
+ const uri = redirectUri ?? this.options.redirectUri;
157
+ this.assertValidRedirectUri(uri, "redirectUri");
158
+ this.ensureAuthServerUrl();
159
+ this.kc.register({ redirectUri: uri });
160
+ }
161
+ /**
162
+ * Log out and redirect to the post-logout URL.
163
+ *
164
+ * @param redirectUri — Override the post-logout redirect.
165
+ */
166
+ logout(redirectUri) {
167
+ this.user = null;
168
+ this.kc.logout({
169
+ redirectUri: redirectUri ?? this.options.postLogoutRedirectUri,
170
+ });
171
+ }
172
+ // ---------------------------------------------------------------------------
173
+ // Token management
174
+ // ---------------------------------------------------------------------------
175
+ /**
176
+ * Get a valid access token, refreshing if needed.
177
+ *
178
+ * @returns The access token string, or `undefined` if not authenticated.
179
+ */
180
+ async getToken() {
181
+ try {
182
+ await this.kc.updateToken(this.options.tokenRefreshBuffer);
183
+ return this.kc.token;
184
+ }
185
+ catch {
186
+ console.error("[FjordAuth] Failed to refresh token");
187
+ return undefined;
188
+ }
189
+ }
190
+ /**
191
+ * Force-refresh the access token.
192
+ *
193
+ * @returns The new access token string, or `undefined` on failure.
194
+ */
195
+ async refreshToken() {
196
+ try {
197
+ await this.kc.updateToken(-1); // Force refresh
198
+ this.syncUser();
199
+ return this.kc.token;
200
+ }
201
+ catch {
202
+ console.error("[FjordAuth] Token refresh failed");
203
+ return undefined;
204
+ }
205
+ }
206
+ /** The raw access token, or `undefined`. */
207
+ get token() {
208
+ return this.kc.token;
209
+ }
210
+ /** The raw ID token, or `undefined`. */
211
+ get idToken() {
212
+ return this.kc.idToken;
213
+ }
214
+ // ---------------------------------------------------------------------------
215
+ // Events
216
+ // ---------------------------------------------------------------------------
217
+ /**
218
+ * Subscribe to an auth event.
219
+ *
220
+ * @returns An unsubscribe function.
221
+ */
222
+ on(event, callback) {
223
+ if (!this.listeners.has(event)) {
224
+ this.listeners.set(event, new Set());
225
+ }
226
+ this.listeners.get(event).add(callback);
227
+ return () => this.listeners.get(event)?.delete(callback);
228
+ }
229
+ emit(event) {
230
+ this.listeners.get(event)?.forEach((cb) => {
231
+ try {
232
+ cb();
233
+ }
234
+ catch (e) {
235
+ console.error(`[FjordAuth] Error in ${event} handler:`, e);
236
+ }
237
+ });
238
+ }
239
+ // ---------------------------------------------------------------------------
240
+ // Internals
241
+ // ---------------------------------------------------------------------------
242
+ syncUser() {
243
+ const profile = this.kc.tokenParsed;
244
+ if (profile) {
245
+ this.user = {
246
+ id: profile.sub ?? "",
247
+ email: profile.email ?? "",
248
+ name: profile.name ??
249
+ [
250
+ profile.given_name,
251
+ profile.family_name,
252
+ ]
253
+ .filter(Boolean)
254
+ .join(" "),
255
+ firstName: profile.given_name,
256
+ lastName: profile.family_name,
257
+ emailVerified: profile.email_verified,
258
+ };
259
+ }
260
+ }
261
+ /**
262
+ * Validate that a redirect URI is a real URL and not an "undefined" string
263
+ * produced by an unset environment variable.
264
+ */
265
+ assertValidRedirectUri(uri, name) {
266
+ if (!uri ||
267
+ uri === "undefined" ||
268
+ uri.startsWith("undefined/") ||
269
+ uri.startsWith("undefined%2F")) {
270
+ throw new Error(`[FjordAuth] Invalid ${name}: "${uri}". ` +
271
+ "This usually means an environment variable used to build the redirect URL is not set. " +
272
+ "Check that all VITE_* / process.env.* variables are defined before the app starts.");
273
+ }
274
+ }
275
+ /**
276
+ * Keycloak may lose authServerUrl after an init timeout.
277
+ * Ensure it's always set correctly before building redirect URLs.
278
+ */
279
+ ensureAuthServerUrl() {
280
+ if (!this.kc.authServerUrl ||
281
+ this.kc.authServerUrl !== this.options.authUrl) {
282
+ this.kc.authServerUrl =
283
+ this.options.authUrl;
284
+ }
285
+ }
286
+ }
287
+ // ---------------------------------------------------------------------------
288
+ // Helpers
289
+ // ---------------------------------------------------------------------------
290
+ function withTimeout(promise, ms, message) {
291
+ return Promise.race([
292
+ promise,
293
+ new Promise((_, reject) => setTimeout(() => reject(new Error(message)), ms)),
294
+ ]);
295
+ }
@@ -0,0 +1,3 @@
1
+ export { FjordAuth } from "./FjordAuth.js";
2
+ export type { FjordAuthOptions, FjordUser, FjordAuthEvent, FjordAuthEventCallback, } from "./types.js";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,YAAY,EACV,gBAAgB,EAChB,SAAS,EACT,cAAc,EACd,sBAAsB,GACvB,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ export { FjordAuth } from "./FjordAuth.js";
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Configuration types for the FjordID client.
3
+ */
4
+ /** Options for initializing a FjordAuth instance. */
5
+ export interface FjordAuthOptions {
6
+ /**
7
+ * Your FjordID domain, e.g. `"your-app.fjordid.eu"`.
8
+ * Used to derive the Keycloak auth URL and realm.
9
+ */
10
+ domain: string;
11
+ /** The OIDC client ID for your application. */
12
+ clientId: string;
13
+ /**
14
+ * Override the Keycloak auth server URL.
15
+ * Defaults to `https://auth.fjordid.eu`.
16
+ */
17
+ authUrl?: string;
18
+ /**
19
+ * The Keycloak realm name.
20
+ * Defaults to `"fjordid"`.
21
+ */
22
+ realm?: string;
23
+ /**
24
+ * Where to redirect after login. Defaults to `window.location.origin`.
25
+ */
26
+ redirectUri?: string;
27
+ /**
28
+ * Where to redirect after logout. Defaults to `window.location.origin`.
29
+ */
30
+ postLogoutRedirectUri?: string;
31
+ /**
32
+ * Enable silent SSO check via hidden iframe.
33
+ * Defaults to `true`. Set to `false` if 3rd-party cookies are blocked.
34
+ */
35
+ silentSso?: boolean;
36
+ /**
37
+ * Timeout in milliseconds for the initial SSO check.
38
+ * Defaults to `10000` (10 seconds).
39
+ */
40
+ initTimeout?: number;
41
+ /**
42
+ * Number of seconds before token expiry to trigger a refresh.
43
+ * Defaults to `30`.
44
+ */
45
+ tokenRefreshBuffer?: number;
46
+ }
47
+ /** Authenticated user profile. */
48
+ export interface FjordUser {
49
+ /** Keycloak subject ID (UUID). */
50
+ id: string;
51
+ /** User's email address. */
52
+ email: string;
53
+ /** User's full name (may be empty). */
54
+ name: string;
55
+ /** User's first name. */
56
+ firstName?: string;
57
+ /** User's last name. */
58
+ lastName?: string;
59
+ /** Whether the email has been verified. */
60
+ emailVerified?: boolean;
61
+ }
62
+ /** Events emitted by FjordAuth. */
63
+ export type FjordAuthEvent = "onReady" | "onAuthSuccess" | "onAuthLogout" | "onAuthError" | "onTokenExpired";
64
+ /** Callback signature for auth events. */
65
+ export type FjordAuthEventCallback = () => void;
66
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,qDAAqD;AACrD,MAAM,WAAW,gBAAgB;IAC/B;;;OAGG;IACH,MAAM,EAAE,MAAM,CAAC;IAEf,+CAA+C;IAC/C,QAAQ,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAE/B;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;OAGG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,kCAAkC;AAClC,MAAM,WAAW,SAAS;IACxB,kCAAkC;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,4BAA4B;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,uCAAuC;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,yBAAyB;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wBAAwB;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,2CAA2C;IAC3C,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,mCAAmC;AACnC,MAAM,MAAM,cAAc,GACtB,SAAS,GACT,eAAe,GACf,cAAc,GACd,aAAa,GACb,gBAAgB,CAAC;AAErB,0CAA0C;AAC1C,MAAM,MAAM,sBAAsB,GAAG,MAAM,IAAI,CAAC"}
package/dist/types.js ADDED
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Configuration types for the FjordID client.
3
+ */
4
+ export {};
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "@fjordid/client",
3
+ "version": "0.1.0",
4
+ "description": "Lightweight JavaScript/TypeScript client for FjordID authentication. Wraps Keycloak OIDC with a simple, developer-friendly API.",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist",
16
+ "README.md"
17
+ ],
18
+ "scripts": {
19
+ "build": "tsc",
20
+ "typecheck": "tsc --noEmit",
21
+ "dev": "tsc --watch"
22
+ },
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "https://github.com/terjetyl/FjordId.git",
26
+ "directory": "packages/client"
27
+ },
28
+ "homepage": "https://fjordid.eu/docs",
29
+ "bugs": {
30
+ "url": "https://github.com/terjetyl/FjordId/issues"
31
+ },
32
+ "publishConfig": {
33
+ "access": "public",
34
+ "registry": "https://registry.npmjs.org/"
35
+ },
36
+ "keywords": [
37
+ "auth",
38
+ "authentication",
39
+ "oidc",
40
+ "oauth2",
41
+ "keycloak",
42
+ "fjordid",
43
+ "gdpr",
44
+ "eu",
45
+ "identity"
46
+ ],
47
+ "license": "MIT",
48
+ "dependencies": {
49
+ "keycloak-js": "^26.0.0"
50
+ },
51
+ "devDependencies": {
52
+ "typescript": "^5.7.3"
53
+ }
54
+ }