@authara/react 0.0.1-trusted.3 → 0.2.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.
@@ -1,23 +1,23 @@
1
1
  import type { AutharaReactClient } from "./contract.js";
2
- import { type GoogleButtonConfiguration } from "./provider-sdks.js";
3
2
  export type GoogleCredential = {
4
- credential: string;
5
- nonce: string;
6
- selectBy?: string;
3
+ code: string;
4
+ redirect_uri: string;
7
5
  };
8
6
  export type AppleAuthorization = {
9
7
  code: string;
10
8
  state: string;
11
9
  };
10
+ export type MicrosoftCredential = {
11
+ credential: string;
12
+ nonce: string;
13
+ };
12
14
  type GoogleHandler = (credential: GoogleCredential) => void;
13
15
  export declare class GoogleService {
14
16
  private readonly client;
15
17
  private optionsPromise?;
16
18
  private sdkPromise?;
17
- private handlers;
18
- private activeState?;
19
19
  constructor(client: AutharaReactClient);
20
- render(element: HTMLElement, configuration: GoogleButtonConfiguration, locale: string | undefined, handler: GoogleHandler): Promise<() => void>;
20
+ prepare(locale: string | undefined, handler: GoogleHandler, errorHandler: (error: Error) => void): Promise<() => void>;
21
21
  private options;
22
22
  private sdk;
23
23
  }
@@ -31,4 +31,14 @@ export declare class AppleService {
31
31
  private renderOptions;
32
32
  private renderOfficialButton;
33
33
  }
34
+ export declare class MicrosoftService {
35
+ private readonly client;
36
+ private optionsPromise?;
37
+ private runtime?;
38
+ private runtimePromise?;
39
+ constructor(client: AutharaReactClient);
40
+ prepare(): Promise<void>;
41
+ authorize(): Promise<MicrosoftCredential>;
42
+ private options;
43
+ }
34
44
  export {};
package/dist/services.js CHANGED
@@ -1,32 +1,34 @@
1
1
  import { loadAppleIdentity, loadGoogleIdentity, } from "./provider-sdks.js";
2
- let stateSequence = 0;
3
- function nextState() {
4
- stateSequence += 1;
5
- return `authara-google-${stateSequence}`;
6
- }
7
2
  export class GoogleService {
8
3
  constructor(client) {
9
4
  this.client = client;
10
- this.handlers = new Map();
11
5
  }
12
- async render(element, configuration, locale, handler) {
6
+ async prepare(locale, handler, errorHandler) {
13
7
  const options = await this.options();
14
- const google = await this.sdk(locale, options);
15
- const state = nextState();
16
- this.handlers.set(state, handler);
17
- google.accounts.id.renderButton(element, {
18
- ...configuration,
19
- locale,
20
- state,
21
- click_listener: () => {
22
- this.activeState = state;
8
+ const google = await this.sdk(locale);
9
+ const client = google.accounts.oauth2.initCodeClient({
10
+ client_id: options.client_id,
11
+ scope: "openid email profile",
12
+ ux_mode: "popup",
13
+ select_account: true,
14
+ callback: (response) => {
15
+ if (response.error) {
16
+ errorHandler(new Error(response.error_description || response.error));
17
+ return;
18
+ }
19
+ if (!response.code) {
20
+ errorHandler(new Error("Google did not return an authorization code."));
21
+ return;
22
+ }
23
+ handler({ code: response.code, redirect_uri: window.location.origin });
24
+ },
25
+ error_callback: (error) => {
26
+ errorHandler(new Error(error.type === "popup_closed"
27
+ ? "Google sign-in was cancelled."
28
+ : "Google sign-in could not be opened."));
23
29
  },
24
30
  });
25
- return () => {
26
- this.handlers.delete(state);
27
- if (this.activeState === state)
28
- this.activeState = undefined;
29
- };
31
+ return () => client.requestCode();
30
32
  }
31
33
  options() {
32
34
  this.optionsPromise ?? (this.optionsPromise = this.client
@@ -37,26 +39,8 @@ export class GoogleService {
37
39
  }));
38
40
  return this.optionsPromise;
39
41
  }
40
- sdk(locale, options) {
41
- this.sdkPromise ?? (this.sdkPromise = loadGoogleIdentity(locale).then((google) => {
42
- google.accounts.id.initialize({
43
- client_id: options.client_id,
44
- nonce: options.nonce,
45
- callback: (response) => {
46
- if (!response.credential)
47
- return;
48
- const state = response.state ?? this.activeState;
49
- if (!state)
50
- return;
51
- this.handlers.get(state)?.({
52
- credential: response.credential,
53
- nonce: options.nonce,
54
- selectBy: response.select_by,
55
- });
56
- },
57
- });
58
- return google;
59
- }));
42
+ sdk(locale) {
43
+ this.sdkPromise ?? (this.sdkPromise = loadGoogleIdentity(locale));
60
44
  return this.sdkPromise;
61
45
  }
62
46
  }
@@ -118,3 +102,75 @@ export class AppleService {
118
102
  }
119
103
  }
120
104
  }
105
+ export class MicrosoftService {
106
+ constructor(client) {
107
+ this.client = client;
108
+ }
109
+ async prepare() {
110
+ if (this.runtime)
111
+ return;
112
+ this.runtimePromise ?? (this.runtimePromise = Promise.all([
113
+ this.options(),
114
+ import("@azure/msal-browser"),
115
+ ])
116
+ .then(async ([options, { PublicClientApplication }]) => {
117
+ const redirectUri = `${window.location.origin}/auth/oauth/microsoft/redirect`;
118
+ const application = new PublicClientApplication({
119
+ auth: {
120
+ clientId: options.client_id,
121
+ authority: options.authority,
122
+ redirectUri,
123
+ },
124
+ cache: { cacheLocation: "sessionStorage" },
125
+ });
126
+ await application.initialize();
127
+ this.runtime = { application, options, redirectUri };
128
+ return this.runtime;
129
+ })
130
+ .catch((error) => {
131
+ this.runtimePromise = undefined;
132
+ throw error;
133
+ }));
134
+ await this.runtimePromise;
135
+ }
136
+ authorize() {
137
+ const runtime = this.runtime;
138
+ if (!runtime) {
139
+ return Promise.reject(new Error("Microsoft authentication is still loading."));
140
+ }
141
+ this.runtime = undefined;
142
+ this.runtimePromise = undefined;
143
+ this.optionsPromise = undefined;
144
+ const resultPromise = runtime.application.loginPopup({
145
+ scopes: ["openid", "profile", "email"],
146
+ nonce: runtime.options.nonce,
147
+ prompt: "select_account",
148
+ redirectUri: runtime.redirectUri,
149
+ overrideInteractionInProgress: true,
150
+ });
151
+ return resultPromise.then((result) => {
152
+ if (!result.idToken) {
153
+ throw new Error("Microsoft did not return an ID token.");
154
+ }
155
+ return {
156
+ credential: result.idToken,
157
+ nonce: runtime.options.nonce,
158
+ };
159
+ });
160
+ }
161
+ options() {
162
+ if (!this.client.getMicrosoftLoginOptions) {
163
+ return Promise.reject({
164
+ status: 404,
165
+ message: "This @authara/browser client does not include Microsoft authentication.",
166
+ });
167
+ }
168
+ this.optionsPromise ?? (this.optionsPromise = this.client
169
+ .getMicrosoftLoginOptions()
170
+ .catch((error) => {
171
+ this.optionsPromise = undefined;
172
+ throw error;
173
+ }));
174
+ return this.optionsPromise;
175
+ }
176
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@authara/react",
3
- "version": "0.0.1-trusted.3",
3
+ "version": "0.2.0",
4
4
  "description": "Official React components for Authara browser authentication",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -22,19 +22,24 @@
22
22
  ],
23
23
  "scripts": {
24
24
  "build": "tsc -p tsconfig.json",
25
+ "build:playground": "tsc -p tsconfig.playground.json --noEmit && vite build --config vite.config.ts",
26
+ "build:playground:package": "npm run build && tsc -p tsconfig.playground.package.json --noEmit && vite build --config vite.config.ts --mode package",
25
27
  "check:contract": "node scripts/check-contract.mjs",
26
- "check:format": "prettier --check \"src/**/*.{ts,tsx}\" \"contract/**/*.ts\" \"scripts/**/*.mjs\"",
27
- "format": "prettier --write \"src/**/*.{ts,tsx}\" \"contract/**/*.ts\" \"scripts/**/*.mjs\"",
28
- "lint": "eslint \"src/**/*.{ts,tsx}\" \"contract/**/*.ts\"",
28
+ "check:error-contract": "node scripts/sync-error-contract.mjs --check",
29
+ "check:format": "prettier --check \"src/**/*.{ts,tsx}\" \"playground/**/*.{ts,tsx,css,html}\" \"contract/**/*.ts\" \"scripts/**/*.mjs\" \"vite.config.ts\" \"docker-compose.playground*.yaml\"",
30
+ "dev": "vite --config vite.config.ts",
31
+ "format": "prettier --write \"src/**/*.{ts,tsx}\" \"playground/**/*.{ts,tsx,css,html}\" \"contract/**/*.ts\" \"scripts/**/*.mjs\" \"vite.config.ts\" \"docker-compose.playground*.yaml\"",
32
+ "lint": "eslint \"src/**/*.{ts,tsx}\" \"playground/**/*.{ts,tsx}\" \"contract/**/*.ts\" \"vite.config.ts\"",
33
+ "sync:error-contract": "node scripts/sync-error-contract.mjs",
29
34
  "test": "vitest run",
30
35
  "prepublishOnly": "npm run check:contract && npm run build"
31
36
  },
32
37
  "peerDependencies": {
33
- "@authara/browser": ">=0.6.0 <1.0.0",
38
+ "@authara/browser": ">=0.11.0 <0.12.0",
34
39
  "react": "^18.0.0 || ^19.0.0"
35
40
  },
36
41
  "devDependencies": {
37
- "@authara/browser": "0.6.0",
42
+ "@authara/browser": "0.11.0",
38
43
  "@eslint/js": "^9.39.2",
39
44
  "@testing-library/react": "^16.3.2",
40
45
  "@types/react": "^19.2.14",
@@ -48,6 +53,11 @@
48
53
  "react-dom": "^19.1.1",
49
54
  "typescript": "^5.9.3",
50
55
  "typescript-eslint": "^8.54.0",
51
- "vitest": "^4.0.18"
56
+ "vite": "^8.3.4",
57
+ "vitest": "^4.0.18",
58
+ "yaml": "2.9.0"
59
+ },
60
+ "dependencies": {
61
+ "@azure/msal-browser": "^5.25.0"
52
62
  }
53
63
  }