Skip to content

Commit e154859

Browse files
authored
Merge pull request #791 from DuendeSoftware/ka-fapi2.0-docs
Add FAPI 2.0 documentation for Duende IdentityServer
2 parents f520570 + 427ef7b commit e154859

File tree

1 file changed

+195
-0
lines changed

1 file changed

+195
-0
lines changed
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
---
2+
title: FAPI 2.0
3+
description: Overview of the FAPI 2.0 implementation in Duende IdentityServer 7.3+
4+
sidebar:
5+
label: FAPI 2.0
6+
badge:
7+
text: v7.3
8+
variant: tip
9+
---
10+
11+
<span data-shb-badge data-shb-badge-variant="default">Added in 7.3</span>
12+
13+
The [FAPI 2.0 Security Profile](https://openid.net/specs/fapi-security-profile-2_0-final.html) is an API security profile based on the OAuth 2.0 Authorization Framework. Its goal is to protect APIs in high-value scenarios and is a set of OAuth Security best current practice (BCP) recommendations. These high-value scenarios include assets typically deployed in the fields of e-health and e-government, which may provide consumers with sensitive data and mission-critical functionality.
14+
15+
Duende IdentityServer implements the FAPI 2.0 BCP features so you can build, deploy, and maintain a FAPI 2.0 Security profile as part of your overall security posture. Let's discuss those features and how to enable them.
16+
17+
## FAPI 2.0 Required Features
18+
19+
To be considered a FAPI 2.0 compliant implementation, your implementation must enable features that provide a heightened security level for your applications. The list of requirements can be found in the specification, but are listed here as well:
20+
21+
### Authorization Servers
22+
23+
When customizing IdentityServer for FAPI 2.0 compliance, follow the rules listed below.
24+
25+
1. Distribute discovery metadata (such as the authorization endpoint) via the metadata document.
26+
2. Reject requests using the resource owner password credentials grant.
27+
3. Only support confidential clients.
28+
4. Only issue sender-constrained access tokens.
29+
5. Use one of the following methods for sender-constrained access tokens: mTLS and DPoP.
30+
6. Authenticate clients using one of the methods of mTLS or `private_key_jwt`.
31+
7. Shall not expose open redirectors.
32+
8. Only accept the issuer identifier value as a string in the `aud` claim received in client authentication assertions.
33+
9. Do not use refresh token rotation except in extraordinary circumstances.
34+
10. If using DPoP, use the server-provided nonce mechanism.
35+
11. Issue authorization codes with a maximum lifetime of 60 seconds.
36+
12. If using DPoP, shall support "Authorization Code Binding to DPoP Key".
37+
13. To accommodate clock offsets, shall accept JWTs with an `iat` or `nbf` timestamp between 0 and 10 seconds in the future, but reject JWTs with an `iat` or `nbf` timestamp greater than 60 seconds in the future.
38+
14. Restrict the privileges associated with an access token to the minimum required for the particular application or use case.
39+
40+
Luckily, many of these rules are enabled by default and do not require any code changes. Let's look at setting up your instance of IdentityServer for FAPI 2.0 compliance.
41+
42+
```csharp
43+
builder.Services.AddIdentityServer(opt =>
44+
{
45+
if (builder.Environment.IsProduction())
46+
{
47+
opt.KeyManagement.KeyPath = "/tmp/keys";
48+
}
49+
opt.KeyManagement.SigningAlgorithms.Add(new SigningAlgorithmOptions(SecurityAlgorithms.RsaSsaPssSha256));
50+
51+
opt.DPoP.SupportedDPoPSigningAlgorithms = [
52+
SecurityAlgorithms.RsaSsaPssSha256,
53+
SecurityAlgorithms.RsaSsaPssSha384,
54+
SecurityAlgorithms.RsaSsaPssSha512,
55+
56+
SecurityAlgorithms.EcdsaSha256,
57+
SecurityAlgorithms.EcdsaSha384,
58+
SecurityAlgorithms.EcdsaSha512
59+
];
60+
opt.SupportedClientAssertionSigningAlgorithms = [
61+
SecurityAlgorithms.RsaSsaPssSha256,
62+
SecurityAlgorithms.RsaSsaPssSha384,
63+
SecurityAlgorithms.RsaSsaPssSha512,
64+
65+
SecurityAlgorithms.EcdsaSha256,
66+
SecurityAlgorithms.EcdsaSha384,
67+
SecurityAlgorithms.EcdsaSha512
68+
];
69+
opt.SupportedRequestObjectSigningAlgorithms = [
70+
SecurityAlgorithms.RsaSsaPssSha256,
71+
SecurityAlgorithms.RsaSsaPssSha384,
72+
SecurityAlgorithms.RsaSsaPssSha512,
73+
74+
SecurityAlgorithms.EcdsaSha256,
75+
SecurityAlgorithms.EcdsaSha384,
76+
SecurityAlgorithms.EcdsaSha512
77+
];
78+
opt.JwtValidationClockSkew = TimeSpan.FromSeconds(10);
79+
80+
})
81+
```
82+
83+
The general configuration for IdentityServer includes two notable changes from what you may see in a typical authorization server implementation.
84+
85+
1. Explicit setting of signing algorithms for JWTs and DPoP to meet FAPI 2.0 compliance, including adding the information to the discovery document.
86+
2. Setting the `JwtValidationClockSkew` to meet the time requirements of FAPI 2.0.
87+
88+
That's it for the server. Next, let's examine how to configure the clients to meet FAPI 2.0 specifications.
89+
90+
### Client Configuration
91+
92+
Clients must also follow strict recommendations to be considered FAPI 2.0 compliant.
93+
94+
1. Support sender-constrained access tokens using one or both methods: mTLS and DPoP.
95+
2. Support client authentication using one or both methods: mTLS and `private_key_jwt`.
96+
3. Send access tokens in the HTTP header
97+
4. Do not expose open redirectors
98+
5. If using `private_key_jwt`, shall use the authorization server's issuer identifier value in the `aud` claim in client authentication assertions. The issuer identifier value shall be sent as a string, not as an array item.
99+
6. Shall support refresh tokens and their rotation;
100+
7. If using mTLS client authentication or mTLS sender-constrained access tokens,`mtls_endpoint_aliases` metadata should be supported.
101+
8. If using DPoP, shall support the server-provided nonce mechanism.
102+
9. Only use authorization server metadata (such as the authorization endpoint) retrieved from the metadata document.
103+
10. Ensure that the issuer URL used to retrieve the authorization server metadata is obtained from an authoritative source and using a secure channel, such that an attacker cannot modify it.
104+
11. Ensure that this issuer URL and the issuer value in the obtained metadata match.
105+
12. Initiate an authorization process only with the end-user's explicit or implicit consent and protect initiation of an authorization process against cross-site request forgery, thereby enabling the end-user to be aware of the context in which a flow was started; and
106+
13. Request authorization with the least privileges necessary for the specific application or use case.
107+
108+
On the client side of your security implementation, a client configuration must also follow these rules:
109+
110+
1. Use the authorization code grant.
111+
2. Use pushed authorization requests.
112+
3. Use PKCE with S256 as the code challenge method.
113+
4. Generate the PKCE challenge for each authorization request and securely bind the challenge to the client and the user agent in which the flow was started.
114+
5. Check the `iss` parameter in the authorization response to prevent mix-up attacks.
115+
6. Only send `client_id` and `request_uri` request parameters to the authorization endpoint (all other authorization request parameters are sent in the pushed authorization request).
116+
7. If using OIDC, nonce parameter values should be no longer than 64 characters.
117+
118+
Again, many of these requirements are already enabled by default as part of IdentityServer. Still, you must change your configuration to enable some requirements explicitly on your client configurations. Let's look at a client that meets FAPI 2.0 compliance.
119+
120+
```csharp
121+
new Client
122+
{
123+
ClientId = "client1",
124+
// 1. set the client secret to use a private key JWT
125+
ClientSecrets = [
126+
new Secret
127+
{
128+
Type = IdentityServerConstants.SecretTypes.JsonWebKey,
129+
Value =
130+
"""
131+
<JWT Key goes here>
132+
"""
133+
}
134+
],
135+
136+
AllowedGrantTypes = GrantTypes.Code,
137+
// 2. explicit redirect URIs for this client
138+
RedirectUris = [
139+
"https://example.com/test/a/duende-fapi2/callback",
140+
"https://example.com/test/a/duende-fapi2/callback?dummy1=lorem&dummy2=ipsum"
141+
],
142+
143+
AllowOfflineAccess = true,
144+
AllowedScopes = [ "openid", "profile", "api" ],
145+
// 3. Require DPoP
146+
RequireDPoP = true,
147+
// 4. Require Pushed Authorization Requests (PAR)
148+
RequirePushedAuthorization = true
149+
},
150+
```
151+
152+
Let's review the four elements that turn a client into a FAPI 2.0-compliant client.
153+
154+
1. Using a private key JWT as a secret.
155+
2. Adding explicit redirect URIs to ensure redirects are for trusted targets.
156+
3. Enable DPoP security for the client.
157+
4. Enable Pushed Authorization Requests
158+
159+
That's it. You now have a FAPI 2.0-compliant client.
160+
161+
Now that our authorization server's client configuration is FAPI 2.0 compliant, we'll need our clients to comply with the requirements.
162+
163+
```csharp
164+
builder.Services.AddAuthentication()
165+
.AddJwtBearer(options =>
166+
{
167+
options.Authority = configuration.Authority;
168+
options.TokenValidationParameters.ValidateAudience = false;
169+
options.MapInboundClaims = false;
170+
171+
options.TokenValidationParameters.ValidTypes = ["at+jwt"];
172+
});
173+
174+
builder.Services.ConfigureDPoPTokensForScheme(JwtBearerDefaults.AuthenticationScheme,
175+
dpopOptions =>
176+
{
177+
dpopOptions.ProofTokenValidationParameters.ValidAlgorithms =
178+
[
179+
SecurityAlgorithms.RsaSsaPssSha256,
180+
SecurityAlgorithms.RsaSsaPssSha384,
181+
SecurityAlgorithms.RsaSsaPssSha512,
182+
183+
SecurityAlgorithms.EcdsaSha256,
184+
SecurityAlgorithms.EcdsaSha384,
185+
SecurityAlgorithms.EcdsaSha512
186+
];
187+
}
188+
);
189+
```
190+
191+
You are now FAPI 2.0 compliant and ready to secure your high-value assets with Duende IdentityServer.
192+
193+
## Private Key JWT vs. mTLS
194+
195+
While the FAPI 2.0 allows for choice in securing communication between the authorization server and clients, we recommend that developers implementing FAPI 2.0 start with private key JWTs before choosing mTLS. Both are supported with Duende IdentityServer, but [implementing mTLS](/identityserver/tokens/client-authentication.md#mutual-tls-client-certificates) is relatively challenging to maintain in a production environment. You are responsible for your deployment and production environments, so you are ultimately best suited to decide which option to move forward with.

0 commit comments

Comments
 (0)