Skip to content

Commit

Permalink
added popup flow (not working yet)
Browse files Browse the repository at this point in the history
  • Loading branch information
robgruen committed Oct 31, 2024
1 parent 7e1ebf6 commit 33ea716
Show file tree
Hide file tree
Showing 5 changed files with 214 additions and 21 deletions.
2 changes: 1 addition & 1 deletion ts/packages/shell/src/renderer/src/auth/authConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,6 @@ export const loginRequest = {
* https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/resources-and-scopes.md
*/
export const tokenRequest = {
scopes: ["User.Read", "Mail.Read"],
scopes: [],
forceRefresh: false // Set this to "true" to skip a cached token and go to the server to get a new token
};
184 changes: 184 additions & 0 deletions ts/packages/shell/src/renderer/src/auth/authPopup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import * as msal from "@azure/msal-browser";
import { AuthResponseCallback } from "./authRedirect.js";
import { loginRequest, msalConfig } from "./authConfig.js";

export class SPAAuthPopup {

private static instance: SPAAuthPopup;
private static initialized: boolean = false;
private static initializedCallbacks: Array<AuthResponseCallback> = new Array<AuthResponseCallback>();

public static getInstance = (): SPAAuthPopup => {
if (!SPAAuthPopup.instance) {
SPAAuthPopup.instance = new SPAAuthPopup();
}

return SPAAuthPopup.instance;
}

public static IsInitialized(): boolean {
return SPAAuthPopup.initialized;
}

public static registerInitializationCallback(callback: AuthResponseCallback) {

if (SPAAuthPopup.initialized) {
throw new Error("Authentication already initialized");
}

this.initializedCallbacks.push(callback);
}

// Create the main myMSALObj instance
// configuration parameters are located at authConfig.js
private myMSALObj: msal.PublicClientApplication;
private username: string = "";
private token: string = "";
private expires: Date | null = new Date();

private constructor() {
this.myMSALObj = new msal.PublicClientApplication(msalConfig);
}

async initalize(signInButton: HTMLButtonElement): Promise<void> {
signInButton.onclick = () => {
if (this.username.length == 0) {
this.signIn();
} else {
this.signOut();
}
}

await this.myMSALObj.initialize();

this.myMSALObj.handleRedirectPromise().then((response) => {
if (response !== null) {
this.username = response.account.username;
this.token = response.accessToken;
this.expires = response.expiresOn;
// welcomeUser(username);
// updateTable(response.account);
} else {
this.selectAccount();

/**
* If you already have a session that exists with the authentication server, you can use the ssoSilent() API
* to make request for tokens without interaction, by providing a "login_hint" property. To try this, comment the
* line above and uncomment the section below.
*/

// myMSALObj.ssoSilent(silentRequest).
// then((response) => {
// welcomeUser(response.account.username);
// updateTable(response.account);
// }).catch(error => {
// console.error("Silent Error: " + error);
// if (error instanceof msal.InteractionRequiredAuthError) {
// signIn();
// }
// });
}

SPAAuthPopup.initialized = true;
})
}

selectAccount () {
/**
* See here for more info on account retrieval:
* https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-common/docs/Accounts.md
*/

const currentAccounts = this.myMSALObj.getAllAccounts();

if (!currentAccounts || currentAccounts.length < 1) {
return;
} else if (currentAccounts.length > 1) {
// Add your account choosing logic here
console.warn("Multiple accounts detected.");
this.username = currentAccounts[0].username;
this.token = this.token;
this.expires = this.expires;
} else if (currentAccounts.length === 1) {
this.username = currentAccounts[0].username
// welcomeUser(currentAccounts[0].username);
// updateTable(currentAccounts[0]);
this.token = this.token;
this.expires = this.expires;
}
}

signIn() {

/**
* You can pass a custom request object below. This will override the initial configuration. For more information, visit:
* https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/request-response-object.md#request
*/

this.myMSALObj.loginPopup(loginRequest)
.then((response) => {
if (response !== null) {
this.username = response.account.username;
this.token = response.accessToken;
this.expires = response.expiresOn;
// welcomeUser(username);
// updateTable(response.account);
} else {
this.selectAccount();

/**
* If you already have a session that exists with the authentication server, you can use the ssoSilent() API
* to make request for tokens without interaction, by providing a "login_hint" property. To try this, comment the
* line above and uncomment the section below.
*/

// myMSALObj.ssoSilent(silentRequest).
// then((response) => {
// welcomeUser(response.account.username);
// updateTable(response.account);
// }).catch(error => {
// console.error("Silent Error: " + error);
// if (error instanceof msal.InteractionRequiredAuthError) {
// signIn();
// }
// });
}
})
.catch(error => {
console.error(error);
});
}

signOut() {

/**
* You can pass a custom request object below. This will override the initial configuration. For more information, visit:
* https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/request-response-object.md#request
*/

// Choose which account to logout from by passing a username.
const logoutRequest = {
account: this.myMSALObj.getAccountByUsername(this.username),
mainWindowRedirectUri: '/signout'
};

this.myMSALObj.logoutPopup(logoutRequest);
}

getToken() { //: Promise<msal.AuthenticationResult | undefined | void> {

if (new Date() < this.expires! && this.token.length > 0) {
//return this.token;
}

return {
token: this.token,
expire: Number(this.expires),
region: "westus",
endpoint: "/subscriptions/b64471de-f2ac-4075-a3cb-7656bca768d0/resourceGroups/openai_dev/providers/Microsoft.CognitiveServices/accounts/octo-aisystems",
};
}
}
36 changes: 21 additions & 15 deletions ts/packages/shell/src/renderer/src/azureSpeech.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
// Licensed under the MIT License.

import * as sdk from "microsoft-cognitiveservices-speech-sdk";
import * as msal from "@azure/msal-browser";
import { SPAAuthRedirect } from "./auth/authRedirect.js";
//import * as msal from "@azure/msal-browser";
//import { SPAAuthRedirect } from "./auth/authRedirect.js";
import { SPAAuthPopup } from "./auth/authPopup.js";
//import { auth } from "aiclient";

export interface TokenResponse {
Expand Down Expand Up @@ -126,20 +127,25 @@ export class AzureSpeech {
// }
// });

const loginResult: msal.AuthenticationResult | undefined | void = await SPAAuthRedirect.getInstance().getToken();

if (loginResult) {
const result: TokenResponse = {
token: loginResult.accessToken,
expire: Number(loginResult.expiresOn),
region: this.region,
endpoint: this.endpoint,
};

return result;
}
//const loginResult: msal.AuthenticationResult | undefined | void = await SPAAuthRedirect.getInstance().getToken();
// if (loginResult) {
// const result: TokenResponse = {
// token: loginResult.accessToken,
// expire: Number(loginResult.expiresOn),
// region: this.region,
// endpoint: this.endpoint,
// };

// return result;
// }

return { token: "", expire: Date.now(), region: this.region, endpoint: this.endpoint};
// return { token: "", expire: Date.now(), region: this.region, endpoint: this.endpoint};


return new Promise<TokenResponse>((resolve) => {
resolve(SPAAuthPopup.getInstance().getToken());
});
};

// private getKeyBasedTokenAsync = async (): Promise<TokenResponse> => {
Expand Down
6 changes: 4 additions & 2 deletions ts/packages/shell/src/renderer/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ import { ShellSettings } from "../../main/shellSettings";
import { AppAgentEvent } from "@typeagent/agent-sdk";
import { CameraView } from "./cameraView";
import { createWebSocket, webapi } from "./webSocketAPI";
import { SPAAuthRedirect } from "./auth/authRedirect";
//import { SPAAuthRedirect } from "./auth/authRedirect";
import { SPAAuthPopup } from "./auth/authPopup";

export function getClientAPI(): ClientAPI {
if (globalThis.api !== undefined) {
Expand Down Expand Up @@ -311,7 +312,8 @@ document.addEventListener("DOMContentLoaded", async function () {

// setup SPA (login)
const loginButton: HTMLButtonElement = document.getElementById("SignIn") as HTMLButtonElement;
SPAAuthRedirect.getInstance().initalize(loginButton);
//SPAAuthRedirect.getInstance().initalize(loginButton);
SPAAuthPopup.getInstance().initalize(loginButton);


const tabs = new TabView(
Expand Down
7 changes: 4 additions & 3 deletions ts/packages/shell/src/renderer/src/webSocketAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import {
import { CommandCompletionResult, RequestMetrics } from "agent-dispatcher";
import { ClientAPI, SpeechToken } from "../../preload/electronTypes";
import { AzureSpeech, TokenResponse } from "./azureSpeech";
import { SPAAuthRedirect } from "./auth/authRedirect";
//import { SPAAuthRedirect } from "./auth/authRedirect";
import { SPAAuthPopup } from "./auth/authPopup";

export const webapi: ClientAPI = {
// TODO: implement
Expand Down Expand Up @@ -184,9 +185,9 @@ export const webapi: ClientAPI = {
}

// wait for auth initialization to complete
if (!SPAAuthRedirect.IsInitialized()) {
if (!SPAAuthPopup.IsInitialized()) {
// wait
SPAAuthRedirect.registerInitializationCallback((response) => {
SPAAuthPopup.registerInitializationCallback((response) => {
const result: TokenResponse = {
token: response.accessToken,
expire: Number(response.expiresOn),
Expand Down

0 comments on commit 33ea716

Please sign in to comment.