Skip to content

Commit 7fdcc87

Browse files
Add extensibility documentation for access token management (#912)
Co-authored-by: Erwin van der Valk <erwin@vandervalk.pro>
1 parent 5ead44e commit 7fdcc87

File tree

2 files changed

+99
-1
lines changed

2 files changed

+99
-1
lines changed
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
---
2+
title: Extensibility
3+
description: Learn how to extend and customize Duende.AccessTokenManagement, including custom token retrieval.
4+
sidebar:
5+
label: Extensibility
6+
order: 50
7+
---
8+
9+
There are several extension points where you can customize the behavior of Duende.AccessTokenManagement.
10+
The extension model is designed to favor composition over inheritance, making it easier to customize and extend while maintaining the library's core functionality.
11+
12+
## Token Retrieval
13+
14+
Token retrieval can be customized by implementing the `AccessTokenRequestHandler.ITokenRetriever` interface.
15+
This interface defines a single method, `GetTokenAsync`, which is called by the `AccessTokenRequestHandler` to retrieve an access token.
16+
17+
A common scenario for this would be if you wanted to implement a different token retrieval flow, that's currently not implemented, such as [Impersonation or Delegation grants (RFC 8693)](https://datatracker.ietf.org/doc/html/rfc8693). Implementing this particular flow is outside the scope of this document.
18+
19+
The following snippet demonstrates how to implement fictive scenario where a custom token retriever dynamically determines which credential flow to use.
20+
21+
```csharp
22+
// CustomTokenRetriever.cs
23+
public class CustomTokenRetriever(
24+
UserTokenRequestParameters parameters,
25+
IClientCredentialsTokenManager clientCredentialsTokenManager,
26+
IUserTokenManager userTokenManagement,
27+
IUserAccessor userAccessor,
28+
ClientCredentialsClientName clientName) : AccessTokenRequestHandler.ITokenRetriever
29+
{
30+
public async Task<TokenResult<AccessTokenRequestHandler.IToken>> GetTokenAsync(
31+
HttpRequestMessage request, CancellationToken ct)
32+
{
33+
// You'll have to make a decision on what token parameters to use,
34+
// and you can override the default parameters.
35+
var param = parameters with
36+
{
37+
Scope = Scope.Parse("some scope"),
38+
ForceTokenRenewal = request.GetForceRenewal() // for retry policies.
39+
};
40+
41+
AccessTokenRequestHandler.IToken token;
42+
43+
// Get the type from current context.
44+
// Using a random number as an example here.
45+
int tokenType = new Random().Next(1, 2);
46+
47+
if (tokenType == 1)
48+
{
49+
var getTokenResult = await clientCredentialsTokenManager
50+
.GetAccessTokenAsync(clientName, param, ct);
51+
52+
if (!getTokenResult.Succeeded)
53+
{
54+
return getTokenResult.FailedResult;
55+
}
56+
57+
token = getTokenResult.Token;
58+
}
59+
else
60+
{
61+
var user = await userAccessor.GetCurrentUserAsync(ct);
62+
63+
var getTokenResult = await userTokenManagement
64+
.GetAccessTokenAsync(user, param, ct);
65+
66+
if (!getTokenResult.Succeeded)
67+
{
68+
return getTokenResult.FailedResult;
69+
}
70+
71+
token = getTokenResult.Token;
72+
}
73+
74+
return TokenResult.Success(token);
75+
}
76+
}
77+
```
78+
79+
A custom token handler can be linked to your `HttpClient` by creating an `AccessTokenRequestHandler` and adding it to the request pipeline:
80+
81+
```csharp
82+
// Program.cs
83+
services.AddHttpClient<YourTypedHttpClient>()
84+
.AddDefaultAccessTokenResiliency()
85+
.AddHttpMessageHandler(provider =>
86+
{
87+
var yourCustomTokenRetriever = new CustomTokenRetriever();
88+
89+
var logger = provider.GetRequiredService<ILogger<AccessTokenRequestHandler>>();
90+
var dPoPProofService = provider.GetRequiredService<IDPoPProofService>();
91+
var dPoPNonceStore = provider.GetRequiredService<IDPoPNonceStore>();
92+
var accessTokenHandler = new AccessTokenRequestHandler(
93+
tokenRetriever: yourCustomTokenRetriever,
94+
dPoPNonceStore: dPoPNonceStore,
95+
dPoPProofService: dPoPProofService,
96+
logger: logger);
97+
});
98+
```

src/content/docs/accesstokenmanagement/upgrading/atm-v3-to-v4.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ Instead of relying on implicit behaviors or inheritance, V4 introduces clearly d
4646

4747
The `AccessTokenHandler` has been restructured to use composition rather than inheritance, simplifying the customization of token handling and increasing testability.
4848

49-
If you wish to implement a custom access token handling process, for example to implement token exchange, you can now implement your own `AccessTokenRequestHandler.ITokenRetriever`.
49+
If you wish to implement a custom access token handling process, for example to implement token exchange, you can now [implement your own `AccessTokenRequestHandler.ITokenRetriever`](/accesstokenmanagement/advanced/extensibility.md#token-retrieval).
5050

5151
### Strongly Typed Configuration
5252

0 commit comments

Comments
 (0)