Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Identity] [Localhost to cloud] New browser credentials #21050

Closed
sadasant opened this issue Mar 25, 2022 · 2 comments
Closed

[Identity] [Localhost to cloud] New browser credentials #21050

sadasant opened this issue Mar 25, 2022 · 2 comments
Assignees
Labels
Azure.Identity Client This issue points to a problem in the data-plane of the library.

Comments

@sadasant
Copy link
Contributor

sadasant commented Mar 25, 2022

Thanks to customer feedback, we have identified that browser developers would benefit from a new authentication approach that matches more closely their experience.

Browser developers tend to work in localhost environments that are deployed to the cloud, and are more often than not involved with the authentication of users in web servers.

This issue is to tie up the development of a new set of features: two credentials specifically designed for browser developers. This credentials are initially called RedirectCredential and PopupCredential.

This issue discusses the current approach for browser developers, then highlights the current challenges, and finally describes how the two new credentials, RedirectCredential and PopupCredential, would solve these challenges.

If you want to try out how the new design looks in comparison to the old design, I’m working on mocked tests here:

Current approach with InteractiveBrowserCredential

The current approach available for browser developers wanting to authenticate their end-users with Azure is to use the browser version of the InteractiveBrowserCredential. This credential uses the Authorization Code flow.

In principle, it's possible to use the InteractiveBrowserCredential from a browser as follows:

const clientId = "my-client-id";
const credential = new InteractiveBrowserCredential({
  clientId,
  // loginStyle: "redirect"
})

If no loginStyle is provided, this credential will use the popup login style.

If no loginStyle is provided, users are able to wait for the token using await, as follows:

const accessToken = await credential.getToken(scope);

This call will open a popup window, and after users finish the interactive flow, the promise will resolve with an access token.

The popup approach is not ideal because many browsers prevent popups from appearing. In those cases, users will need to manually enable popups before continuing to work with the browser app.

If users prefer to use the redirect approach, they will need to specify the loginStyle as redirect. When doing so, users will need to process the redirection on page load. The best way to do this at the moment is to initialize the credential and call to getToken on page load, as follows:

window.onload = async () => {
  const clientId = "my-client-id";
  const credential = new InteractiveBrowserCredential({
    clientId,
    // loginStyle: "redirect"
  })
  const accessToken = await credential.getToken(scope);
  // Once they have a token, silent authentication will work in the rest of the app.
}

Once they have a token, silent authentication will work in the rest of the application.

The credential is able to authenticate using the received code from the redirection at any point in the application, however, the longer it takes for the code to reach the point where a token is requested (explicitly through getToken, or implicitly through one of the SDK client methods), the higher the risk to have something else change the hash of the page, thus losing the ability to authenticate, and forcing the credential to trigger the redirection the next time getToken is called.

It's also important to note that, once a user is authenticated, a single credential can't authenticate another user, or logout.

Logout is particularly important because the endpoint used to authenticate single-page applications can cache the credentials that succeeded the last time, making it impossible to willingly change the authenticated user unless the browser local cached memory on the Azure endpoint side is cleared.

Challenges of the current approach

  1. Although the loginStyle parameter allows users to change how the authentication happens, it is currently implied that changing this property will have no effect on how the architecture of the application needs to be, however not setting this parameter disables authentication in most browsers (popup) and setting the parameter to “redirect” is disruptive for browser applications.
  2. The default popup behavior is disabled in most browsers, and the redirect behavior is disruptive for the browser application.
  3. After the redirection happens, the credential retrieves the authentication code from the URL, which might not be obvious for users and could cause unintended behaviors.
  4. No acknowledgement of the possibility of multiple users being authenticated in the browser.
  5. There's no current way to pass metadata to the authentication endpoint, to know how to route the redirection or how to resume from a previously running process in the browser application.
  6. No way to log out.

Concept of a new approach

In a new plugin package named @azure/identity-spa (after the spa redirect endpoint on the AAD app registration), two credentials could be provided RedirectCredential and PopupCredential.

These credentials would:

  • Throw on Node.js (not isomorphic).
  • Accept a state parameter through the options bag:
  • Not automatically authenticate on getToken. They would throw AuthenticationRequiredError to indicate that the interactive authentication needs to be triggered by using the authenticate() method.

Additionally, the RedirectCredential would have a method called onPageLoad() to clearly indicate when to process the parameters received after the redirection ended, and that would also retrieve the state parameter initially.

const state = JSON.stringify({
  origin: window.location.href,
  user: user.id
})
const credential = new RedirectCredential(clientId, { state });
const client = new Client("url", credential);

window.onload = async () => {
  const { state } = await credential.onPageLoad();
  console.log({ state });
}

async function authenticate(): boolean {
  // To manually authenticate only if getToken throws an AuthenticationRequiredError
  try {
    await credential.getToken(scope);
    return true;
  } catch(e) {
    if (e.name === "AuthenticationRequiredError") {
      await credential.authenticate(scope, { state });
      // Redirect happens.
    }
    return false;
  }
}

async function getAzureValues() {
  await client.method(); // Will throw if the token is expired, or if the user hasn't authenticated.
}
@sadasant
Copy link
Contributor Author

sadasant commented Mar 25, 2022

Question from Karishma: Can we open a new tab instead of redirection?

How that can work:

  • If on getToken we open a new tab instead of redirecting it would do half of the trick, because we would be in a new tab, right
  • To finish the experience, on page load of that new tab, once the user finishes authentication, it should close the tab.
  • After closing the tab, we should be back in the first window, where maybe a promise is waiting for localStorage to contain the account information of the authenticated user.

Contingency:

  • If the user closes the tab, we could have a timeout after which we would throw “AuthenticationRequiredError”.

So, it is possible! However, two questions:

  1. Can MSAL do this?
  2. How hard would it be to do this without MSAL? (maybe partially with MSAL, at least to retrieve the account from the cache).

Note: Maybe this comment specifically should be in a separate issue?

@sadasant sadasant removed their assignment May 9, 2022
@xirzec xirzec modified the milestones: [2022] May, [2022] June May 17, 2022
@KarishmaGhiya KarishmaGhiya modified the milestones: [2022] June, [2022] July Jun 7, 2022
@xirzec xirzec modified the milestones: 2022-07, 2022-08 Jul 8, 2022
@xirzec xirzec modified the milestones: 2022-08, 2022-09 Aug 9, 2022
azure-sdk pushed a commit to azure-sdk/azure-sdk-for-js that referenced this issue Oct 10, 2022
azure-sdk pushed a commit to azure-sdk/azure-sdk-for-js that referenced this issue Oct 14, 2022
[2022-04-01-preview] Add New Api-version for Microsoft.ApiManagement (Azure#20399)

* Adds base for updating Microsoft.ApiManagement from version preview/2021-12-01-preview to version 2022-04-01-preview

* Updates readme

* Updates API version in new specs and examples

* APIM Auth Servers (Azure#19234)

* APIM Auth Servers

* adding x-ms-identifiers

* removing some weird, invisible special char

* formatting

* oAuth2AuthenticationSettings moved to AuthSettings

* Formatting

Co-authored-by: Milan Zolota <mizolota@microsoft.com>

* API Management Authorization Endpoints (Azure#19615)

* Add blockchain to latest profile

* Add additional types

* add authorizations definitions

* authorizations operations

* add examples

* update readme

* fix examples

* fix linter delete errors

* address CI validation errors

* prettier fix

* update to 2022-04

* fix readme

* Update specification/apimanagement/resource-manager/Microsoft.ApiManagement/preview/2022-04-01-preview/apimauthorizationproviders.json

Co-authored-by: Sean Kim <seaki@microsoft.com>

* update versions

* Apply suggestions from code review

Co-authored-by: Mark Cowlishaw <markcowl@microsoft.com>
Co-authored-by: Annaji Sharma Ganti <anganti@microsoft.com>
Co-authored-by: Annaji Sharma Ganti <42851022+annaji-msft@users.noreply.github.com>

* Move Long running Create Operation from Location based to Azure-AsyncOperation Header (Azure#19733)

* azure-asyncOperation

* prettier

* fix(apim): Add missing 'metrics' property to diagnostics contract in 2022-04-01-preview (Azure#20317)

* apim /PUT apis import add translateRequiredQueryParameters (Azure#20333)

* [2022-04-01-preview] Replace resource with proxyresource and TrackedResource (Azure#20461)

* replace resource with proxyresource

* revert to proxyresource

* Add type object to authorization definitions (Azure#20631)

Authorization definitions were missing "type": "object", and this change adds that key/value pair

* Add type object to policy fragment definition (Azure#20585)

* APIM Open ID Connect providers (Azure#20622)

* APIM Open ID Connect providers

* added new proeprties for update

* prettier

* [APIM] Add Nat Gateway (Azure#19990)

* Update apimdeployment.json

* Create ApiManagementCreateServiceWithNatGatewayEnabled.json

* fix typo in file

* Change Nat Gateway property to enum

* modify type of natgateway state

* update property name

* add example reference

* small fix in example

* rename to  outboundPublicIPAddresses

Co-authored-by: Samir Solanki <samirsolanki@outlook.com>

* [2022-04-01-preview] MIgrate2Stv2 API (Azure#20504)

* migrate2stv2

* updated to post

* 202 and location

* add body to 202

* remove body from 202

Co-authored-by: Vatsa Patel <vatsapatel@microsoft.com>
Co-authored-by: Samir Solanki <samirsolanki@outlook.com>
Co-authored-by: vatsapatel@microsoft.colm <vatsapatel@microsoft.colm>

* Address Authorizations MissingTypeObject errors (Azure#20919)

* Add forgotten If-Match header (Azure#20920)

* Add forgotten If-Match header

`If-Match` header for the `DeleteAuthorizationAccessPolicy.json file` was forgotten. This change adds the wildcard character for the `If-Match` header for that file.

* Update ApiManagementDeleteAuthorization.json

* Use common types for specs and count as readonly (Azure#21023)

* common types

* count readonly

* Sasolank/more review comments (Azure#21025)

* XML

* proxy to gateway

* Update Authorizations Spec (Azure#21027)

* Update definitions.json

Update wording for PostGetLoginLink endpoint description

* Update apimauthorizationproviders.json

Add 201 response to all Authorization PUT requests

* Updated examples and fixed formatting

There was a formatting issue within apimauthorizationproviders.json, and the Authorization examples needed to be updated with the new 201 responses for creating/updating Authorization entities.

* Add long-running-operation key/value

Added x-ms-long-running-operation: true to Authorization PUT requests

* Remove long-running-operations

* readonly revert (Azure#21050)

* Set  SchemaContract.Document as required. (Azure#20110)

* Updated documentation of the SchemaContract. Server use to return code 500 in case SchemaContract.Document is null. That issue was fixed in the APIM and server will return proper response code.

* Fix AzureApiValidation

* update field with properties

* revert remaining readonly on collection (Azure#21051)

* Change to camel casing for "accesspolicies" (Azure#21070)

* Change to camel casing for "accesspolicies"

* More camel casing updates for access policies

* list example fixed (Azure#21089)

* fix definition (Azure#21110)

* upgrade to v3 for common types (Azure#21109)

* upgrade to v3

* Space

* revert to v2 proxyResource

Co-authored-by: Milan Zolota <Hardell@users.noreply.github.com>
Co-authored-by: Milan Zolota <mizolota@microsoft.com>
Co-authored-by: Sean D Kim <seandkim14@gmail.com>
Co-authored-by: Mark Cowlishaw <markcowl@microsoft.com>
Co-authored-by: Annaji Sharma Ganti <anganti@microsoft.com>
Co-authored-by: Annaji Sharma Ganti <42851022+annaji-msft@users.noreply.github.com>
Co-authored-by: Tom Kerkhove <kerkhove.tom@gmail.com>
Co-authored-by: Korolev Dmitry <deagle.gross@gmail.com>
Co-authored-by: Logan Zipkes <44794089+LFZ96@users.noreply.github.com>
Co-authored-by: Rafał Mielowski <mielex@gmail.com>
Co-authored-by: malincrist <92857141+malincrist@users.noreply.github.com>
Co-authored-by: GuanchenIntern <109827715+GuanchenIntern@users.noreply.github.com>
Co-authored-by: VatsaPatel <vatsapatel13@gmail.com>
Co-authored-by: Vatsa Patel <vatsapatel@microsoft.com>
Co-authored-by: vatsapatel@microsoft.colm <vatsapatel@microsoft.colm>
Co-authored-by: Maxim Agapov <103097563+agapovm@users.noreply.github.com>
@xirzec xirzec modified the milestones: 2022-09, 2022-12 Nov 1, 2022
@xirzec xirzec modified the milestones: 2022-12, 2023-02 Jan 11, 2023
@scottaddie scottaddie added the Client This issue points to a problem in the data-plane of the library. label Jan 18, 2023
@xirzec xirzec removed this from the 2023-02 milestone Mar 31, 2023
Copy link

Hi @sadasant, we deeply appreciate your input into this project. Regrettably, this issue has remained inactive for over 2 years, leading us to the decision to close it. We've implemented this policy to maintain the relevance of our issue queue and facilitate easier navigation for new contributors. If you still believe this topic requires attention, please feel free to create a new issue, referencing this one. Thank you for your understanding and ongoing support.

@github-actions github-actions bot closed this as not planned Won't fix, can't repro, duplicate, stale Mar 25, 2024
@github-actions github-actions bot locked and limited conversation to collaborators Mar 25, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Azure.Identity Client This issue points to a problem in the data-plane of the library.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants