Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion astro/src/content/docs/bff/extensibility/tokens.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,4 +126,21 @@ app.MapRemoteBffApiEndpoint(
.WithAccessTokenRetriever<ImpersonationAccessTokenRetriever>();
```

The `GetAccessTokenAsync` method will be invoked on every call to APIs that use the access token retriever. If retrieving the token is an expensive operation, you may need to cache it. It is up to your retriever code to perform caching.
Custom access token retrievers can also be used with [YARP routes and clusters](/bff/fundamentals/apis/yarp.md#custom-access-token-retriever).
Use the `WithAccessTokenRetriever<T>()` extension method on a `RouteConfig` or `ClusterConfig`,
or set the `Duende.Bff.Yarp.AccessTokenRetriever` metadata key in JSON configuration:

```csharp
// YARP route with custom retriever
new RouteConfig()
{
RouteId = "impersonation",
ClusterId = "cluster1",
Match = new RouteMatch { Path = "/api/impersonation/{**catch-all}" }
}.WithAccessToken(RequiredTokenType.User)
.WithAccessTokenRetriever<ImpersonationAccessTokenRetriever>()
```

The `GetAccessTokenAsync` method will be invoked on every call to APIs that use the access token retriever.
If retrieving the token is an expensive operation, you may need to cache it. It is up to your retriever code
to perform caching.
90 changes: 89 additions & 1 deletion astro/src/content/docs/bff/fundamentals/apis/yarp.md
Original file line number Diff line number Diff line change
Expand Up @@ -281,4 +281,92 @@ app.MapReverseProxy(proxyApp =>
{
proxyApp.UseAntiforgeryCheck();
});
```
```

## Custom Access Token Retriever

You can specify a custom [`IAccessTokenRetriever`](/bff/extensibility/tokens.md#per-route-customized-token-retrieval) on
YARP routes and clusters. This allows you to customize how access tokens are obtained for proxied requests — for
example, to perform token exchange for delegation or impersonation scenarios.

### Code Configuration

A custom retriever can be set at the **route level** or the **cluster level**. Route-level retrievers take precedence
over cluster-level retrievers.

Use the `WithAccessTokenRetriever<T>()` extension method on a `RouteConfig`:

```csharp
// Route-level retriever
new RouteConfig()
{
RouteId = "impersonation",
ClusterId = "cluster1",

Match = new RouteMatch
{
Path = "/api/impersonation/{**catch-all}"
}
}.WithAccessToken(RequiredTokenType.User)
.WithAccessTokenRetriever<ImpersonationAccessTokenRetriever>()
.WithAntiforgeryCheck()
```

Or `ClusterConfig`:

```csharp
// Cluster-level retriever (applies to all routes using this cluster)
new ClusterConfig()
{
ClusterId = "cluster-with-impersonation",
Destinations = new Dictionary<string, DestinationConfig>(StringComparer.OrdinalIgnoreCase)
{
{ "destination1", new() { Address = "https://api.example.com" } },
}
}.WithAccessTokenRetriever<ImpersonationAccessTokenRetriever>()
```

### JSON Configuration

Use the `Duende.Bff.Yarp.AccessTokenRetriever` metadata key with an assembly-qualified type name:

```json
{
"ReverseProxy": {
"Routes": {
"impersonation": {
"ClusterId": "cluster1",
"Match": {
"Path": "/api/impersonation/{**catch-all}"
},
"Metadata": {
"Duende.Bff.Yarp.TokenType": "User",
"Duende.Bff.Yarp.AntiforgeryCheck": "true",
"Duende.Bff.Yarp.AccessTokenRetriever": "MyApp.ImpersonationAccessTokenRetriever, MyApp"
}
}
},
"Clusters": {
"cluster-with-impersonation": {
"Destinations": {
"destination1": {
"Address": "https://api.example.com"
}
},
"Metadata": {
"Duende.Bff.Yarp.AccessTokenRetriever": "MyApp.ImpersonationAccessTokenRetriever, MyApp"
}
}
}
}
}
```

### Precedence

When a retriever is specified on both the route and the cluster, the **route-level retriever takes precedence**. This
allows you to set a default retriever on a cluster and override it for specific routes.

:::note
The custom retriever type must implement `IAccessTokenRetriever` and be registered in the service collection.
:::
Loading