Add documentation for Entity Framework Core and MongoDB integrations

This commit is contained in:
Kévin Chalet
2022-01-11 17:28:52 +01:00
parent 7cf51db471
commit eb3fd55b65
19 changed files with 237 additions and 43 deletions

View File

@@ -0,0 +1,210 @@
# Choosing the right flow
OpenIddict offers built-in support for all the standard flows defined by the
[OAuth 2.0](https://tools.ietf.org/html/rfc6749) and [OpenID Connect](https://openid.net/specs/openid-connect-core-1_0.html) core specifications:
[the authorization code flow](https://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth),
[the implicit flow](https://openid.net/specs/openid-connect-core-1_0.html#ImplicitFlowAuth),
[the hybrid flow](https://openid.net/specs/openid-connect-core-1_0.html#HybridFlowAuth) (which is basically a mix between the first two flows),
[the resource owner password credentials grant](https://tools.ietf.org/html/rfc6749#section-4.3) and
[the client credentials grant](https://tools.ietf.org/html/rfc6749#section-4.4).
While not specific to OpenIddict, choosing the best flow(s) for your application is an **important prerequisite**
when implementing your own authorization server ; so here's a quick overview of the different OAuth 2.0/OpenID Connect flows:
------------------------
## Non-interactive flows
### Resource owner password credentials flow (not recommended for new applications)
Directly inspired by [basic authentication](https://en.wikipedia.org/wiki/Basic_access_authentication), the resource owner password credentials grant
(abbreviated *ROPC*) is conceptually **the simplest OAuth 2.0 flow**: the client application asks the user his username/password, sends a token request
to the authorization server with the user credentials (and depending on the client authentication policy defined by the authorization server,
its own client credentials) and gets back an access token it can use to retrieve the user's resources.
![Resource owner password credentials flow](choosing-the-right-flow/resource-owner-password-flow.png)
```http
POST /connect/token HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded
grant_type=password&username=johndoe&password=A3ddj3w
```
```http
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
```
> [!CAUTION]
> This flow is **not recommended by the OAuth 2.0 specification** as it's the only grant type where **the user password is directly exposed to the client application**,
> which breaks the principle of least privilege and **makes it unsuitable for third-party client applications that can't be fully trusted by the authorization server**.
> While popular and trivial to implement (as it doesn't involve any redirection or consent form and unlike interactive flows, doesn't require implementing
> cross-site request forgery (XSRF) countermeasures to prevent session fixation attacks), **its use in new applications is not recommended**. Instead,
> users are encouraged to use the authorization code flow, that doesn't expose passwords to client applications and is not limited to password authentication.
<!-- more -->
-------------------------------------------------------------------------------
### Client credentials grant (recommended for machine-to-machine communication)
The client credentials grant is almost identical to the resource owner password credentials grant, except it's been specifically designed for **client-to-server scenarios**
(no user is involved in this flow): the client application sends a token request containing its credentials and gets back an access token it can use to query its own resources.
![Client credentials flow](choosing-the-right-flow/client-credentials-flow.png)
```http
POST /connect/token HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials&client_id=s6BhdRkqt3&client_secret=gX1fBat3bV
```
```http
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
```
> [!NOTE]
> Unlike the resource owner password credentials grant, **client authentication is not optional** when using the client credentials grant and
> **OpenIddict will always reject unauthenticated token requests**, [as required by the OAuth 2.0 specification](https://tools.ietf.org/html/rfc6749#section-4.4.2).
>
> This means that **you CAN'T use the client credentials grant with public applications** like browser,
> mobile or desktop applications, as they are not able to keep their credentials secret.
--------------------
## Interactive flows
### Authorization code flow (recommended for new applications)
While the authorization code flow is probably the most complicated flow (as it involves both **user-agent redirections and backchannel communication**), it's
**the recommended flow for any scenario involving end users, whether they log in using a password, a PIN, a smart card or even an external provider**.
In return for its complexity, this flow has a great advantage when used in server-side applications: the `access_token` cannot be intercepted by the user agent.
There are basically 2 steps in the authorization code flow: the authorization request/response and the token request/response.
![Authorization code flow](choosing-the-right-flow/authorization-code-flow.png)
- **Step 1: the authorization request**
In this flow, the client application always initiates the authentication process by generating an authorization request including
the mandatory `response_type=code` parameter, its `client_id`, its `redirect_uri` and optionally, a `scope` and a `state` parameter
[that allows flowing custom data and helps mitigate XSRF attacks](https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest).
> [!NOTE]
> In most cases, the client application will simply return a 302 response with a `Location` header to redirect the user agent to the authorization endpoint,
> but depending on the OpenID Connect client you're using, POST requests might also be supported to allow you to send large authorization requests.
> This feature [is usually implemented using an auto-post HTML form](https://github.com/aspnet/Security/pull/392).
```http
HTTP/1.1 302 Found
Location: https://server.example.com/authorize?response_type=code&client_id=s6BhdRkqt3&state=af0ifjsldkj&redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb
```
```http
GET /connect/authorize?response_type=code&client_id=s6BhdRkqt3&state=af0ifjsldkj&redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb HTTP/1.1
Host: server.example.com
```
The way the identity provider handles the authorization request is implementation-specific but in most cases, a consent form
is displayed to ask the user if he or she agrees to share his/her personal data with the client application.
![Consent form](choosing-the-right-flow/consent-form.png)
When the consent is given, the user agent is redirected back to the client application with **a unique and short-lived token**
named *authorization code* that the client will be able to exchange with an access token by sending a token request.
```http
HTTP/1.1 302 Found
Location: https://client.example.org/cb?code=SplxlOBeZQQYbYS6WxSbIA&state=af0ifjsldkj
```
> [!WARNING]
> To prevent XSRF/session fixation attacks, **the client application MUST ensure that the `state` parameter returned by the identity provider
> corresponds to the original `state`** and stop processing the authorization response if the two values don't match.
> [This is usually done by generating a non-guessable string and a corresponding correlation cookie](https://tools.ietf.org/html/rfc6749#section-10.12).
- **Step 2: the token request**
When the client application gets back an authorization code, it must immediately reedem it for an access token by sending a `grant_type=authorization_code` token request.
> [!NOTE]
> To help the identity provider [mitigate counterfeit clients attacks](https://tools.ietf.org/html/rfc6819#section-4.4.1.7), the original `redirect_uri` must also be sent.
>
> If the client application is a confidential application (i.e an application that has been assigned client credentials), authentication is required.
```http
POST /connect/token HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb&client_id=s6BhdRkqt3&client_secret=gX1fBat3bV&scope=openid
```
```http
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
```
> [!NOTE]
> To increase security, additional parameters such as `code_challenge` and `code_challenge_method` can be specified to bind the authorization code
> that will be returned by the authorization endpoint to the original authorization request. This mechanism is known as
> [Proof Key for Code Exchange](../configuration/proof-key-for-code-exchange.md) and is fully supported by OpenIddict.
--------------------------------------------------------
### Implicit flow (not recommended for new applications)
The implicit flow is similar to the authorization code flow, **except there's no token request/response step**: the access token is directly returned
to the client application as part of the authorization response in the URI fragment (or in the request form when using `response_mode=form_post`).
![Implicit flow](choosing-the-right-flow/implicit-flow.png)
```http
GET /connect/authorize?response_type=token&client_id=s6BhdRkqt3&redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb&scope=openid&state=af0ifjsldkj&nonce=n-0S6_WzA2Mj HTTP/1.1
Host: server.example.com
```
```http
HTTP/1.1 302 Found
Location: https://client.example.org/cb#access_token=SlAV32hkKG&token_type=bearer&expires_in=3600&state=af0ifjsldkj
```
> [!CAUTION]
> Initially designed for browser applications, this flow is inherently less secure than the authorization code flow and doesn't support
> [Proof Key for Code Exchange](https://tools.ietf.org/html/rfc7636). As such, using it in new applications is not recommended.
> [!WARNING]
> To prevent XSRF/session fixation attacks, **the client application MUST ensure that the `state` parameter returned by the identity provider
> corresponds to the original `state`** and stop processing the authorization response if the two values don't match.
> [This is usually done by generating a non-guessable string and a corresponding value stored in the local storage](https://tools.ietf.org/html/rfc6749#section-10.12).
>
> When using the implicit flow, **the client application MUST also ensure that the access token was not issued
> to another application to prevent [confused deputy attacks](https://stackoverflow.com/a/17439317/542757).**
> With OpenID Connect, this can be done by using `response_type=id_token token` and checking the `aud` claim
> of the JWT identity token, that must correspond or contain the `client_id` of the client application.
```
> [!CAUTION]
> Initially designed for browser applications, this flow is inherently less secure than the authorization code flow and doesn't support
> [Proof Key for Code Exchange](https://tools.ietf.org/html/rfc7636). As such, using it in new applications is not recommended.
> [!WARNING]
> To prevent XSRF/session fixation attacks, **the client application MUST ensure that the `state` parameter returned by the identity provider
> corresponds to the original `state`** and stop processing the authorization response if the two values don't match.
> [This is usually done by generating a non-guessable string and a corresponding value stored in the local storage](https://tools.ietf.org/html/rfc6749#section-10.12).
>
> When using the implicit flow, **the client application MUST also ensure that the access token was not issued
> to another application to prevent [confused deputy attacks](https://stackoverflow.com/a/17439317/542757).**
> With OpenID Connect, this can be done by using `response_type=id_token token` and checking the `aud` claim
> of the JWT identity token, that must correspond or contain the `client_id` of the client application.

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

207
guides/getting-started.md Normal file
View File

@@ -0,0 +1,207 @@
# Getting started
**To implement a custom OpenID Connect server using OpenIddict, the simplest option is to clone one of the official samples** from the [openiddict-samples repository](https://github.com/openiddict/openiddict-samples).
If you don't want to start from one of the recommended samples, you'll need to:
- **Install the [.NET Core 3.1 (or later) tooling](https://www.microsoft.com/net/download)**.
- **Have an existing project or create a new one**: when creating a new project using Visual Studio's default ASP.NET Core template,
using **individual user accounts authentication** is strongly recommended as it automatically includes the default ASP.NET Core Identity UI, based on Razor Pages.
- **Update your `.csproj` file** to reference the latest `OpenIddict` packages:
```xml
<PackageReference Include="OpenIddict.AspNetCore" Version="3.1.1" />
<PackageReference Include="OpenIddict.EntityFrameworkCore" Version="3.1.1" />
```
- **Configure the OpenIddict core, server and validation services** in `Startup.ConfigureServices`.
Here's an example for the client credentials grant, used in machine-to-machine scenarios:
```csharp
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddDbContext<ApplicationDbContext>(options =>
{
// Configure Entity Framework Core to use Microsoft SQL Server.
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"));
// Register the entity sets needed by OpenIddict.
// Note: use the generic overload if you need to replace the default OpenIddict entities.
options.UseOpenIddict();
});
services.AddOpenIddict()
// Register the OpenIddict core components.
.AddCore(options =>
{
// Configure OpenIddict to use the Entity Framework Core stores and models.
// Note: call ReplaceDefaultEntities() to replace the default entities.
options.UseEntityFrameworkCore()
.UseDbContext<ApplicationDbContext>();
})
// Register the OpenIddict server components.
.AddServer(options =>
{
// Enable the token endpoint.
options.SetTokenEndpointUris("/connect/token");
// Enable the client credentials flow.
options.AllowClientCredentialsFlow();
// Register the signing and encryption credentials.
options.AddDevelopmentEncryptionCertificate()
.AddDevelopmentSigningCertificate();
// Register the ASP.NET Core host and configure the ASP.NET Core options.
options.UseAspNetCore()
.EnableTokenEndpointPassthrough();
})
// Register the OpenIddict validation components.
.AddValidation(options =>
{
// Import the configuration from the local OpenIddict server instance.
options.UseLocalServer();
// Register the ASP.NET Core host.
options.UseAspNetCore();
});
// Register the worker responsible of seeding the database with the sample clients.
// Note: in a real world application, this step should be part of a setup script.
services.AddHostedService<Worker>();
}
```
- **Make sure the ASP.NET Core authentication middleware is correctly registered at the right place**:
```csharp
public void Configure(IApplicationBuilder app)
{
app.UseDeveloperExceptionPage();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(options =>
{
options.MapControllers();
options.MapDefaultControllerRoute();
});
}
```
- **Update your Entity Framework Core context registration to register the OpenIddict entities**:
```csharp
services.AddDbContext<ApplicationDbContext>(options =>
{
// Configure Entity Framework Core to use Microsoft SQL Server.
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"));
// Register the entity sets needed by OpenIddict.
// Note: use the generic overload if you need to replace the default OpenIddict entities.
options.UseOpenIddict();
});
```
> [!NOTE]
> By default, the OpenIddict Entity Framework Core integration uses `string` as the default type for primary keys.
> To use a different type, read [Entity Framework Core integration : Use a custom primary key type](~/integrations/entity-framework-core.md#use-a-custom-primary-key-type).
- **Create your own authorization controller:**
Implementing a custom authorization controller is required to allow OpenIddict to create tokens based on the identities and claims you provide.
Here's an example for the client credentials grant:
```csharp
public class AuthorizationController : Controller
{
private readonly IOpenIddictApplicationManager _applicationManager;
public AuthorizationController(IOpenIddictApplicationManager applicationManager)
=> _applicationManager = applicationManager;
[HttpPost("~/connect/token"), Produces("application/json")]
public async Task<IActionResult> Exchange()
{
var request = HttpContext.GetOpenIddictServerRequest();
if (!request.IsClientCredentialsGrantType())
{
throw new NotImplementedException("The specified grant is not implemented.");
}
// Note: the client credentials are automatically validated by OpenIddict:
// if client_id or client_secret are invalid, this action won't be invoked.
var application = await _applicationManager.FindByClientIdAsync(request.ClientId) ??
throw new InvalidOperationException("The application cannot be found.");
// Create a new ClaimsIdentity containing the claims that
// will be used to create an id_token, a token or a code.
var identity = new ClaimsIdentity(TokenValidationParameters.DefaultAuthenticationType, Claims.Name, Claims.Role);
// Use the client_id as the subject identifier.
identity.AddClaim(Claims.Subject,
await _applicationManager.GetClientIdAsync(application),
Destinations.AccessToken, Destinations.IdentityToken);
identity.AddClaim(Claims.Name,
await _applicationManager.GetDisplayNameAsync(application),
Destinations.AccessToken, Destinations.IdentityToken);
return SignIn(new ClaimsPrincipal(identity),
OpenIddictServerAspNetCoreDefaults.AuthenticationScheme);
}
}
```
- **Register your client application** (e.g from an `IHostedService` implementation):
```csharp
public class Worker : IHostedService
{
private readonly IServiceProvider _serviceProvider;
public Worker(IServiceProvider serviceProvider)
=> _serviceProvider = serviceProvider;
public async Task StartAsync(CancellationToken cancellationToken)
{
using var scope = _serviceProvider.CreateScope();
var context = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
await context.Database.EnsureCreatedAsync();
var manager =
scope.ServiceProvider.GetRequiredService<IOpenIddictApplicationManager>();
if (await manager.FindByClientIdAsync("console") is null)
{
await manager.CreateAsync(new OpenIddictApplicationDescriptor
{
ClientId = "console",
ClientSecret = "388D45FA-B36B-4988-BA59-B187D329C207",
DisplayName = "My client application",
Permissions =
{
Permissions.Endpoints.Token,
Permissions.GrantTypes.ClientCredentials
}
});
}
}
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}
```
Before running the application, make sure the database is updated with OpenIddict tables by running `Add-Migration` and `Update-Database`.

13
guides/index.md Normal file
View File

@@ -0,0 +1,13 @@
# Introduction
## What's OpenIddict?
OpenIddict was born in late 2015 and was initially based on **[AspNet.Security.OpenIdConnect.Server](https://github.com/aspnet-contrib/AspNet.Security.OpenIdConnect.Server)**
(codenamed ASOS), a low-level OpenID Connect server middleware forked from OWIN/Katana's `OAuthAuthorizationServerMiddleware`. In 2020, ASOS was merged into OpenIddict 3.0
to form a unified stack under the OpenIddict umbrella, while still offering an easy-to-use approach for new users and a low-level experience for advanced users.
## Why an OpenID Connect server?
Adding an OpenID Connect server to your application **allows you to support token authentication**.
It also allows you to manage all your users using local password or an external identity provider (e.g. Facebook or Google) for all your
applications in one central place, with the power to control who can access your API and the information that is exposed to each client.

View File

@@ -0,0 +1,217 @@
# Migrate to OpenIddict 3.0
## What's new?
The announcement listing the changes introduced in this milestone can be found [here](https://kevinchalet.com/2020/12/23/openiddict-3-0-general-availability/).
> [!IMPORTANT]
> **Migrating to OpenIddict 3.0 requires making changes to your database**: existing properties have been reworked and new ones have been added to support the new features.
## Update your packages references
For that, update your `.csproj` file to reference the `OpenIddict.AspNetCore` 3.x metapackage:
```xml
<ItemGroup>
<PackageReference Include="OpenIddict.AspNetCore" Version="3.1.1" />
<PackageReference Include="OpenIddict.EntityFrameworkCore" Version="3.1.1" />
</ItemGroup>
```
## Ensure your application doesn't reference legacy/unsupported packages
As part of the AspNet.Security.OpenIdConnect.Server/OpenIddict merge, the ASOS packages and 2 OpenIddict packages have been marked as legacy
and are no longer supported. Make sure your application (or intermediate libraries) don't reference any of these packages:
| Package name |
|------------------------------------------|
| AspNet.Security.OpenIdConnect.Extensions |
| AspNet.Security.OpenIdConnect.Primitives |
| AspNet.Security.OpenIdConnect.Server |
| |
| Owin.Security.OpenIdConnect.Extensions |
| Owin.Security.OpenIdConnect.Server |
| |
| AspNet.Security.OAuth.Introspection |
| AspNet.Security.OAuth.Validation |
| |
| Owin.Security.OAuth.Introspection |
| Owin.Security.OAuth.Validation |
| |
| OpenIddict.Models |
| OpenIddict.Mvc |
> [!IMPORTANT]
> If your application references the `OpenIdConnectConstants` class, update it to use `OpenIddictConstants` instead.
## Update the references to the Entity Framework Core/Entity Framework 6/MongoDB models
If your application references the `OpenIddictApplication`, `OpenIddictAuthorization`, `OpenIddictScope` or `OpenIddictToken` models, update these reference to use
their new names: `OpenIddict[provider name]Application`, `OpenIddict[provider name]Authorization`, `OpenIddict[provider name]Scope` and `OpenIddict[provider name]Token`
(e.g when using MongoDB: `OpenIddictMongoDbApplication`, `OpenIddictMongoDbAuthorization`, `OpenIddictMongoDbScope` and `OpenIddictMongoDbToken`).
## Enable ASP.NET Core integration in the server and validation options
With the base server and validation stacks being decoupled from ASP.NET Core, you now have to explicitly register the ASP.NET Core host in the server/validation options:
```csharp
services.AddOpenIddict()
.AddServer(options =>
{
options.UseAspNetCore();
})
.AddValidation(options =>
{
options.UseAspNetCore();
});
```
## Enable the authorization, logout and token endpoints pass-through mode
Unless you're using OpenIddict's events model to handle authorization, logout and token requests, you'll need to enable
the pass-through mode for these endpoints, so that requests can reach your authorization controller as in the previous versions:
```csharp
services.AddOpenIddict()
.AddServer(options =>
{
options.UseAspNetCore()
.EnableAuthorizationEndpointPassthrough()
.EnableLogoutEndpointPassthrough()
.EnableTokenEndpointPassthrough();
});
```
## Enable ASP.NET Core Data Protection support to ensure existing tokens can still be validated
For that, call `options.UseDataProtection()` in both the server and validation options:
```csharp
services.AddOpenIddict()
.AddServer(options =>
{
options.UseDataProtection();
})
.AddValidation(options =>
{
options.UseDataProtection();
});
```
## Use the new request caching APIs, if applicable
In 3.0, the `OpenIddictServerBuilder.EnableRequestCaching()` API - that enabled request caching for both authorization and logout request -
was replaced by 2 separate methods. If your application depends on request caching, don't forget to enable it when migrating to 3.0:
```csharp
services.AddOpenIddict()
.AddServer(options =>
{
options.UseAspNetCore()
.EnableAuthorizationRequestCaching()
.EnableLogoutRequestCaching();
});
```
## Replace JSON.NET by `System.Text.Json`
If you use JSON.NET to serialize or deserialize `OpenIdConnectMessage`, `OpenIdConnectRequest` or `OpenIdConnectResponse` instances,
consider moving to `System.Text.Json` when migrating to OpenIddict 3.0, as 3.0 no longer includes a built-in JSON.NET `JsonConverter` for their
equivalent in 3.0 (i.e `OpenIddictMessage`, `OpenIddictRequest` and `OpenIddictResponse`).
In most cases, this should be as simple as replacing `JsonConvert.SerializeObject()`/`JsonConvert.DeserializeObject()`
by their `System.Text.Json` equivalent: `JsonSerializer.Serialize()`/`JsonSerializer.Deserialize()`.
## Replace calls to the `AuthenticationTicket` extensions by their new `ClaimsPrincipal` equivalent:
OpenIddict 3.0 no longer uses the `AuthenticationTicket` type provided by ASP.NET Core. Instead, everything is now stored in the `ClaimsPrincipal` instance.
If you have calls like `ticket.SetScopes()` or `ticket.SetResources()`, use their new equivalents (e.g `principal.SetScopes()` or `principal.SetResources()`).
## Use the new authentication schemes
In 3.0, the constants used as the ASP.NET Core authentication schemes have changed:
| Old constant name | New constant name (ASP.NET Core host) |
|---------------------------------------------------|-------------------------------------------------------------|
| OpenIddictServerDefaults.AuthenticationScheme | OpenIddictServerAspNetCoreDefaults.AuthenticationScheme |
| OpenIddictValidationDefaults.AuthenticationScheme | OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme |
| OAuthValidationDefaults.AuthenticationScheme | OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme |
> [!NOTE]
> In 3.0, the OpenIddict server ASP.NET Core handler supports authenticating userinfo requests. As such, if you use the pass-through mode
> to handle userinfo requests in your own userinfo MVC action, consider using `OpenIddictServerAspNetCoreDefaults.AuthenticationScheme`
> instead of `OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme` for your userinfo endpoint to avoid validating access tokens twice.
## Update your application to work with the new `scope` format
In OpenIddict 3.0, the format of the `scope` claim used in JWT tokens has changed from a JSON array to a single space-separated claim
to match [the JWT access token specification](https://datatracker.ietf.org/doc/html/rfc9068). To ensure your authorization policies
still work after migrating, consider using the `principal.HasScope()` extension to determine whether a scope has been granted:
```csharp
services.AddAuthorization(options =>
{
options.AddPolicy("MyPolicy", builder =>
{
builder.RequireAuthenticatedUser();
builder.RequireAssertion(context => context.User.HasScope("api1"));
});
});
```
Alternatively, you can use the check the presence of the private OpenIddict `oi_scp` claims that use the same format as in 2.x (i.e one claim per scope value):
```csharp
services.AddAuthorization(options =>
{
options.AddPolicy("MyPolicy", builder =>
{
builder.RequireAuthenticatedUser();
builder.RequireClaim(Claims.Private.Scope, "api1");
});
});
```
> [!CAUTION]
> These 2 options only work with the OpenIddict validation handler as the `oi_scp` claims are not populated by the JWT bearer handler developped by Microsoft.
> If you can't migrate to the OpenIddict validation handler, consider splitting the standard `scope` claim manually to determine whether it contains a specific value.
## Add and apply migrations, if necessary
If your application uses Entity Framework Core or Entity Framework 6, add a migration to react to the schema changes listed below and apply it.
### Updated properties
| Table | Column name | Observations |
|--------------------------|----------------|-----------------------------------------------------------------------------|
| OpenIddictAuthorizations | Subject | The column is now nullable to support the device authorization flow. |
| OpenIddictTokens | CreationDate | For broader database support, this column is a now a `DateTime` instance. |
| OpenIddictTokens | ExpirationDate | For broader database support, this column is a now a `DateTime` instance. |
| OpenIddictTokens | Subject | The column is now nullable to support the device authorization flow. |
### Added properties
| Table | Column name | Type | Nullable |
|--------------------------|----------------|----------|----------|
| OpenIddictAuthorizations | CreationDate | DateTime | Yes |
| OpenIddictTokens | RedemptionDate | DateTime | Yes |
## If necessary, enable hybrid flow support in the server options
In 2.0, the hybrid flow was automatically enabled if both the authorization code and implicit flows were enabled. In 3.0, this is no longer true
and the hybrid flow MUST be explicitly opted in. If you use the hybrid flow, make sure your application calls the `options.AllowHybridFlow()` method:
```csharp
services.AddOpenIddict()
.AddServer(options =>
{
options.AllowHybridFlow();
});
```
## Update your applications to grant them the appropriate response type permissions
New response type permissions - enforced by default - [have been introduced in 3.0](/configuration/application-permissions.html#response-type-permissions).
If you have many applications to migrate, you can use [this script](https://github.com/openiddict/openiddict-core/issues/1138#issuecomment-713681158)
to infer appropriate response type permissions using the already granted grant types.

20
guides/toc.yml Normal file
View File

@@ -0,0 +1,20 @@
- name: Introduction
href: index.md
- name: Getting started
href: getting-started.md
- name: Choosing the right flow
href: choosing-the-right-flow.md
- name: Migration guides
items:
- name: Migration from 2.0 to 3.0
href: migration/20-to-30.md
- name: External resources
items:
- name: OAuth 2.0 specification
href: https://tools.ietf.org/html/rfc6749
- name: OpenID Connect specification
href: https://openid.net/specs/openid-connect-core-1_0.html