Skip to content
This repository was archived by the owner on Sep 8, 2025. It is now read-only.

Commit acf47d2

Browse files
authored
Fix/refresh with scope (#374)
* fix: cannot set scope on refresn token #373 * test: set requested scope in response * style: change parameter order
1 parent e786a87 commit acf47d2

File tree

3 files changed

+75
-2
lines changed

3 files changed

+75
-2
lines changed

src/OidcClient/OidcClient.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -312,13 +312,15 @@ public virtual async Task<UserInfoResult> GetUserInfoAsync(string accessToken, C
312312
/// </summary>
313313
/// <param name="refreshToken">The refresh token.</param>
314314
/// <param name="backChannelParameters">Back-channel parameters</param>
315+
/// <param name="scope">Space separated list of the requested scopes.</param>
315316
/// <param name="cancellationToken">The cancellation token.</param>
316317
/// <returns>
317318
/// A token response.
318319
/// </returns>
319320
public virtual async Task<RefreshTokenResult> RefreshTokenAsync(
320321
string refreshToken,
321-
Parameters backChannelParameters = null,
322+
Parameters backChannelParameters = null,
323+
string scope = null,
322324
CancellationToken cancellationToken = default)
323325
{
324326
_logger.LogTrace("RefreshTokenAsync");
@@ -336,7 +338,8 @@ public virtual async Task<RefreshTokenResult> RefreshTokenAsync(
336338
ClientAssertion = Options.ClientAssertion,
337339
ClientCredentialStyle = Options.TokenClientCredentialStyle,
338340
RefreshToken = refreshToken,
339-
Parameters = backChannelParameters
341+
Parameters = backChannelParameters,
342+
Scope = scope
340343
}, cancellationToken).ConfigureAwait(false);
341344

342345
if (response.IsError)
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
using System;
2+
using System.Net.Http;
3+
using System.Threading;
4+
using System.Threading.Tasks;
5+
using Xunit;
6+
7+
namespace IdentityModel.OidcClient.Tests
8+
{
9+
public class OidcClientTests
10+
{
11+
[Fact]
12+
public async Task RefreshTokenAsync_with_scope_should_set_http_request_scope_parameter()
13+
{
14+
var scope = Guid.NewGuid().ToString();
15+
var sut = new OidcClient(new OidcClientOptions
16+
{
17+
Authority = "https://exemple.com",
18+
ProviderInformation = new ProviderInformation
19+
{
20+
IssuerName = "https://exemple.com",
21+
AuthorizeEndpoint = "https://exemple.com/connect/authorize",
22+
TokenEndpoint = "https://exemple.com/connect/token"
23+
},
24+
Policy = new Policy
25+
{
26+
Discovery = new Client.DiscoveryPolicy
27+
{
28+
RequireKeySet = false,
29+
}
30+
},
31+
ClientId = "test",
32+
Scope = "openid profile offline_access",
33+
RedirectUri = "test://authentication/login-callback",
34+
HttpClientFactory = o =>
35+
{
36+
return new HttpClient(new FakeHttpMessageHandler
37+
{
38+
Func = async r =>
39+
{
40+
var content = await r.Content.ReadAsStringAsync();
41+
Assert.Contains($"scope={scope}", content);
42+
return new HttpResponseMessage
43+
{
44+
Content = new StringContent($@"{{
45+
""access_token"": ""23af3183-a712-40c7-86f8-d784705c8a78"",
46+
""refresh_token"": ""23af3183-a712-40c7-86f8-d784705c8a79"",
47+
""expires_in"": 3600,
48+
""token_type"": ""Bearer"",
49+
""scope"": ""{scope}""
50+
}}")
51+
};
52+
}
53+
});
54+
}
55+
});
56+
57+
var result = await sut.RefreshTokenAsync("test", scope: scope);
58+
59+
Assert.NotNull(result);
60+
}
61+
62+
class FakeHttpMessageHandler : HttpMessageHandler
63+
{
64+
public Func<HttpRequestMessage, Task<HttpResponseMessage>> Func { get; set; }
65+
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
66+
=> Func(request);
67+
}
68+
}
69+
}

test/OidcClient.Tests/RefreshTokenDelegatingHandlerTests.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,7 @@ public TestableOidcTokenRefreshClient(TestTokens tokens, TimeSpan delayForRefres
244244

245245
public override async Task<RefreshTokenResult> RefreshTokenAsync(string refreshToken,
246246
Parameters backChannelParameters = null,
247+
string scope = null,
247248
CancellationToken cancellationToken = default)
248249
{
249250
var newTokens = _tokens.RefreshUsing(refreshToken);

0 commit comments

Comments
 (0)