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

[msal-core] Fix response type configuration by basing it mainly on scopes #2022

Merged
merged 36 commits into from
Aug 17, 2020
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
4eb8a1b
Add initial respnse type tests to UserAgentApplication
hectormmg Jul 22, 2020
8787b8b
Enable empty scopes array for login API calls
hectormmg Jul 22, 2020
66e2f6b
Enable getting an id token from acquireToken APIs if only OIDC scopes…
hectormmg Jul 22, 2020
e4ae5cb
Add new getTokenType logic for response type configuration for acquir…
hectormmg Jul 23, 2020
02c2b6c
Finish passing tests for response_type behavior for acquireToken APIs
hectormmg Jul 23, 2020
5d9f580
Refactor getTokenType for code readability and correct class responsi…
hectormmg Jul 23, 2020
fe4fd4d
Refactor clientId translation and OIDC scope addition into ScopeSet.n…
hectormmg Jul 23, 2020
42a8d51
Fix bug where clientId was being spliced even when it wasn't the only…
hectormmg Jul 23, 2020
e2fea1a
Update documentation on scopes behavior
hectormmg Jul 23, 2020
73deeae
Remove unnecessary imports from UrlUtils
hectormmg Jul 23, 2020
2910c01
Add response-types.md documentation and update the links on scopes.md
hectormmg Jul 23, 2020
d1103a8
Merge branch 'dev' into scopes-and-response-types
Jul 23, 2020
b60819b
Add missing OIDC spec links to response types doc
hectormmg Jul 24, 2020
078a4c8
Merge branch 'dev' into scopes-and-response-types
Jul 24, 2020
179c4e3
Response types doc update to address feedback
hectormmg Jul 24, 2020
d0f1181
Merge branch 'scopes-and-response-types' of github.com:AzureAD/micros…
hectormmg Jul 24, 2020
f3e09b6
Refactor clientId translation to translate in request validation, the…
hectormmg Jul 24, 2020
4f7c390
Add warning that document only applies to msal-core to response types…
hectormmg Jul 24, 2020
c2012ab
Merge branch 'dev' into scopes-and-response-types
Jul 27, 2020
b78de45
Change default request signature to use OIDC scopes rather than clien…
hectormmg Jul 27, 2020
cdaa8af
Refactor onlyContainsOidcScopes method to skip unnecessary subtractio…
hectormmg Jul 27, 2020
84f4677
Simplify ternary operator to a logical comparison in ScopeSet.onlyCon…
hectormmg Jul 27, 2020
f23a0bf
Merge branch 'dev' into scopes-and-response-types
Jul 27, 2020
3cbf76a
Add TLDRs to new docs on scopes and response types
hectormmg Jul 27, 2020
a0a7e09
Merge branch 'scopes-and-response-types' of github.com:AzureAD/micros…
hectormmg Jul 27, 2020
962c8be
Fix typos in response-types doc
hectormmg Jul 27, 2020
2e868ff
Add custom scope example to scopes doc
hectormmg Jul 27, 2020
5081e43
Merge branch 'dev' into scopes-and-response-types
Jul 27, 2020
e74efb6
Fix typos and style issues in new docs
hectormmg Jul 28, 2020
7bcaaf2
Merge branch 'scopes-and-response-types' of github.com:AzureAD/micros…
hectormmg Jul 28, 2020
d0e6654
Merge branch 'dev' into scopes-and-response-types
Jul 28, 2020
206ec9a
Add closing bold asterisks in response-types doc
hectormmg Jul 28, 2020
9819533
Merge branch 'scopes-and-response-types' of github.com:AzureAD/micros…
hectormmg Jul 28, 2020
d1b4d89
Fix merge conflicts with dev
hectormmg Aug 10, 2020
441025e
Change files
hectormmg Aug 10, 2020
c862dec
Update beachball change file with PR in description
hectormmg Aug 10, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
72 changes: 72 additions & 0 deletions lib/msal-core/docs/response-types.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Response Types

## Definition and Types
The `msal@1.x` library, in compliance of both the OAuth 2.0 protocol specification as well as the OpenID Connect specification, defines and supports three different `response types`:

* token
* id_token
* id_token token

The **`msal@1.x` library does not support the `code` response type because it does not implement the Authorization Code grant. If you are looking to implement the Authorization Code grant type, consider the [msal-browser](https://github.com/AzureAD/microsoft-authentication-library-for-js/tree/dev/lib/msal-browser) library.**

The listed response types are possible values for the `response_type` parameter in OAuth 2.0 HTTP requests. Assuming a valid request, this parameter determines what kind of token is sent back by the Secure Token Service (STS) that `msal@1.x` requests access and ID tokens from.

| Response Type | Specification that defines it | Expected token type from successful request | Action |
| ------------- | ----------------------------- | ------------------------------------------- | ------ |
| `token` |[OAuth 2.0](https://tools.ietf.org/html/rfc6749#section-3.1.1) | Access Token | Authorization |
| `id_token`| [OpenID Connect](https://openid.net/specs/openid-connect-core-1_0.html#Authentication) | ID Token | Authentication |
|`id_token token`| [OpenID Connect](https://openid.net/specs/openid-connect-core-1_0.html#Authentication) | Access Token and ID token | Authorization & Authentication |

**Note: Given that `msal@1.x` uses the OAuth 2.0 Implicit Flow exclusively, which leverages URL fragments for token reception, it is important to be mindful of URL length limitations. In some cases, getting both an access token and ID token in the same URL may cause unexpected or incorrect behavior.**
hectormmg marked this conversation as resolved.
Show resolved Hide resolved

## Response Type configuration and behavior

The `response_type` attribute presented above is not a directly configurable element of an authorization server request in `msal@1.x`. However, it is important to understand the way `msal@1.x` determines which response type is set and, therefore, what kind of token the developer can expect for each scenario. The factors that come into consideration when setting the request's `response_type` parameter are the following:
hectormmg marked this conversation as resolved.
Show resolved Hide resolved

1. The `msal@1.x` API called
hectormmg marked this conversation as resolved.
Show resolved Hide resolved
2. Whether the account passed into the request configuration matches the account in the MSAL cache
3. The contents of the `scopes` array in the Authorization Request Configuration object. For more information on `scopes` configuration, please consult the [Scopes](/docs/scopes.md) document.

**Important note: Login APIs will always set `response_type=id_token`. It doesn not matter whether a matching account is passed in or what scopes are configured.** The fact that there is no extra considerations for `login` APIs to determine the `response_type` make it the most important factor.
hectormmg marked this conversation as resolved.
Show resolved Hide resolved

Login APIs include:

* loginRedirect
* loginPopup
* ssoSilent

In other words, whenever you call `loginRedirect` or `loginPopup` to sign a user in, you should expect to receive an ID token if the request is successful.

The following section contains quick reference tables for both `login` and `acquireToken` APIs that accurately map the request configuration to the resulting response type.

## Quick reference tables

### Login APIs

Applies to: `loginRedirect`, `loginPopup`, `ssoSilent`

| Input scopes | Account passed in | Response Type Result |
| ----------------- | ------------ | -------------------- |
| Any case | Any case | `id_token`|

### Acquire Token APIs

Applies to: `acquireTokenRedirect`, `acquireTokenPopup`, `acquireTokenSilent`

* *OIDC scopes: any combination of `openid` and/or `profile`*
* *OIDC scopes only: Same as OIDC scopes but with no other scopes in the array*

| Input scopes | Account passed in | Response Type Result |
| ----------------- | ------------ | -------------------- |
| ClientId as only scope | Any case | `id_token`|
| OIDC scopes only | Any Case | `id_token`|
hectormmg marked this conversation as resolved.
Show resolved Hide resolved
| ClientId with OIDC scopes | Any case | `id_token token` |
| Resource scope(s) only | Matches cached account object | `token` |
| Resource scope(s) and ClientId | Matches cached account object | `token` |
| Resource scope(s) with OIDC scopes | Matches cached account object | `id_token token` |
hectormmg marked this conversation as resolved.
Show resolved Hide resolved
| Resource scope(s) only | Doesn't match cached account object | `id_token token` |
| Resource scope(s) with OIDC scopes | Doesn't match cached account object | `id_token token` |

**Note: As seen in the table above, when ClientId is not the only scope, it is assumed to be a resource scope with no special behavior.**


88 changes: 88 additions & 0 deletions lib/msal-core/docs/scopes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# Scope Configuration and Behavior

## Contents
* [Scopes](#scopes)
* [Scope Functions](#scope-functions)
* [Scope Types](#scope-types)
* [Resource scopes for Authorization](#resource-scopes-for-authorization)
* [OpenID Connect Scopes for Authentication](#openid-connect-scopes-for-authentication)
* [Scopes Behavior](#scopes-behavior)
* [Default Scopes in Authorization Requests](#default-scopes-on-authorization-requests)
* [Special OIDC Scopes behavior cases](#special-oidc-scopes-behavior-cases)
## Scopes

Microsoft identity platform access tokens, which `msal@1.x` acquires in compliance with the OAuth 2.0 protocol specification, are issued to applications as proof of authorization on behalf of a user for a certain resource. The issuing of these tokens is not only specific to an `audience`, or application, but also specific to a set of `scopes` or permissions.

### Scope Functions

#### Function of scopes in OAuth 2.0

The main function of the `scopes` configuration, per the [OAuth 2.0 Access Token Scope Reference](https://tools.ietf.org/html/rfc6749#section-3.3), is to determine the permissions for which an application requests `authorization` on behalf of the user. Said function is both supported and covered by `msal@1.x` and the Microsoft identity platform in general. For more information on the regular function of authorization scopes, please consult the official [Microsoft identity platform documentation](https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-permissions-and-consent).

#### Special use of scopes in msal@1.x

In addition to the global concept and use of `scopes`, it is important to understand that `msal@1.x` gives scopes a special use that adds to the importance of their configuration. In short, `msal@1.x` allows developers to leverage certain scopes in order to determine the `response_type` for the final request. For more information on the way the scopes configuration determines the `response_type` parameter, please refer to the [Response Types Document](/docs/response-types.md).
hectormmg marked this conversation as resolved.
Show resolved Hide resolved



## Scope Types

As far as `msal@1.x` is concerned, there are two main types of `scopes` that can be configured in a token request.

### Resource scopes for Authorization

`Resource scopes` are the main type of access token `scopes` that `msal@1.x` deals with. These are the `scopes` that represent permissions for specific actions against a particular resource. In other words, these `scopes` determine what actions and resources the requesting application is `authorized` to access on behalf of the user. The following are some examples of the `resource scopes` that the [Microsoft Graph](https://docs.microsoft.com/en-us/graph/overview) service can authorize an application for given the user's consent:

* `User.Read`: Authorizes the application to read a user's account details.
* `Mail.Read`: Authorizes the application to read a user's e-mails.

Including resource scopes in the configuration for a token request doesn't always mean that the response will include an **access token** for said scopes. In the specific case of `msal@1.x`'s `login` APIs (`loginRedirect`, `loginPopup`), adding resource scopes may allow the user to **constent** to said scopes ahead of time, but successful `login` API calls always result in an **ID Token, not an access token**, being returned.

### OpenID Connect Scopes for Authentication

`OpenID Connect (OIDC) scopes` are a specific set of scopes that can be added to requests when `authenticating` a user. In most cases, `OIDC scopes` are added to configure the claims included in an ID Token ([OIDC Reference](https://openid.net/specs/openid-connect-core-1_0.html#ScopeClaims) / [Microsoft Docs](https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-permissions-and-consent#openid-connect-scopes)). Some services, such as the Secure Token Service that `msal@1.x` acquires tokens from, also use OIDC scopes in their internal logic. For this reason, it is important to understand and pay attention to the special behavior `msal@1.x` has around OIDC scopes (described in the [next section](#default-scopes-on-authorization-requests)).

The OIDC scopes that `msal@1.x` pays particular attention to are outlined in the table below.

| OIDC Scope | Required by OIDC Specification | Function | OIDC Reference | Microsoft Docs |
| ---------- | ------------------------------ | -------- | -------------- | -------------- |
| `openid`| Mandatory | Main `OIDC scope` that indicates a request for `authentication` [per the OIDC specification](https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest). In AAD requests, this is the scope that prompts the "Sign in" permission that a user can consent to. | [Authentication Request](https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest)| [Permissions and consent in the Microsoft identity platform endpoint](https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-protocols-oidc#send-the-sign-in-request)|
|`profile`| Optional | Used for ID Token `claims` configuration. Adds the end-user's default profile information as a claim to the ID token returned | [Requesting Claims using Scopes Values](https://openid.net/specs/openid-connect-core-1_0.html#ScopeClaims) | [OpenID Permissions](https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-permissions-and-consent)|


## Scopes Behavior

### Default Scopes on Authorization Requests

Understanding how `OIDC scopes` configure the claims included in an authentication response's ID Token is important when using `msal@1.x` to acquire said ID Tokens. However, there is an important note to be made on how the `openid` and `profile` scopes are added by `msal@1.x` to all server requests by default that does not directly relate to the OpenID Connect specification.

Like previously mentioned, the Secure Token Service that `msal@1.x` requests access and ID tokens from also makes use of the `openid` and `profile` scopes. Specifically, the STS expects these two scopes in order to configure and provide the `client_info` parameter in authorization and authentication responses. The `msal@1.x` library depends on the contents of `client_info` in order to successfuly cache tokens and, therefore, provide silent token acquisition as a feature.
hectormmg marked this conversation as resolved.
Show resolved Hide resolved
hectormmg marked this conversation as resolved.
Show resolved Hide resolved

**For this reason, whether or not the developer adds the `openid` or `profile` scopes to their request configuration, `msal@1.x` will make sure they are included before sending the request to the STS.**

### Special OIDC Scopes behavior cases

The following is a list of practical implications and examples of the default scope behavior described in the previous section.

- If the scopes array does not include either `openid` or `profile`, whichever is missing (could be both) will be added to the scopes array by default before the request is sent out.
hectormmg marked this conversation as resolved.
Show resolved Hide resolved

Examples:

```js
{ scopes: ['User.Read'] } // becomes { scopes: ['User.Read', 'openid', 'profile'] } before the request is sent

{ scopes: ['User.Read', 'openid'] } // becomes { scopes ['User.Read', 'openid', 'profile']} before the request is sent

{ scopes: ['User.Read', 'profile'] } // becomes { scopes ['User.Read', 'profile', 'openid']} before the request is sent
```
- ClientId is removed form the scopes array when it is the only scope in the configuration.If it is not the only scope, it is treated as a resource scope and will be sent in the final server request.
hectormmg marked this conversation as resolved.
Show resolved Hide resolved

Examples:

```js
{ scopes: ['YOUR_CLIENT_ID'] } // becomes { scopes: ['openid', 'profile'] } before the request is sent (ClientId is spliced out)

{ scopes: ['YOUR_CLIENT_ID', 'User.Read'] } // becomes { scopes ['YOUR_CLIENT_ID', 'User.Read', 'openid', 'profile']} before the request is sent (ClientId is treated as resource scope and therefore not spliced out)

{ scopes: ['YOUR_CLIENT_ID', 'openid'] } // becomes { scopes ['YOUR_CLIENT_ID', 'openid', 'profile']} before the request is sent
```