Skip to content

Commit 3aa7079

Browse files
Improve tokens.
1 parent 0d31be7 commit 3aa7079

11 files changed

Lines changed: 170 additions & 27 deletions

File tree

csharp/Squidex.ClientLibrary/Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
<PackageTags>Squidex HeadlessCMS</PackageTags>
1616
<PublishRepositoryUrl>true</PublishRepositoryUrl>
1717
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
18-
<Version>22.1.0</Version>
18+
<Version>22.2.0</Version>
1919
</PropertyGroup>
2020

2121
<PropertyGroup Condition="'$(GITHUB_ACTIONS)' == 'true'">
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// ==========================================================================
2+
// Squidex Headless CMS
3+
// ==========================================================================
4+
// Copyright (c) Squidex UG (haftungsbeschraenkt)
5+
// All rights reserved. Licensed under the MIT license.
6+
// ==========================================================================
7+
8+
namespace Squidex.ClientLibrary.Tests;
9+
10+
public class ApiKeyAuthTokenTests
11+
{
12+
[Fact]
13+
public void Should_serialize_as_header()
14+
{
15+
var sut = new ApiKeyAuthToken("MyApp", "MyKey");
16+
17+
var header = sut.SerializeAsHeader();
18+
Assert.Equal(("Authorization", "ApiKey MyApp:MyKey"), header);
19+
}
20+
21+
[Fact]
22+
public void Should_serialize_as_query()
23+
{
24+
var sut = new ApiKeyAuthToken("MyApp", "MyKey");
25+
26+
var header = sut.SerializeAsQuery();
27+
Assert.Equal(("api_key", "MyApp%3AMyKey"), header);
28+
}
29+
}

csharp/Squidex.ClientLibrary/Squidex.ClientLibrary.Tests/BasicClientServiceTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ public async Task Should_not_try_authenticate_again_if_it_failed(int retryHours,
8080

8181
private class CountUrlHandler : DelegatingHandler
8282
{
83-
public Dictionary<string, int> Counts { get; private set; } = new Dictionary<string, int>();
83+
public Dictionary<string, int> Counts { get; private set; } = [];
8484

8585
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
8686
CancellationToken cancellationToken)

csharp/Squidex.ClientLibrary/Squidex.ClientLibrary.Tests/BasicClientTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ public async Task Should_get_content()
4646
[Fact(Skip = "No permissions.")]
4747
public async Task Should_get_content_with_invalid_token_for_anonymous_access()
4848
{
49-
((CachingAuthenticator)sut.Options.Authenticator).SetToCache(sut.Options.AppName,
50-
new AuthToken("Authorization", "Bearer TOKEN"), DateTimeOffset.MaxValue);
49+
((CachingAuthenticator)sut.Options.Authenticator)
50+
.SetToCache(sut.Options.AppName, new BearerAuthToken("TOKEN"), DateTimeOffset.MaxValue);
5151

5252
var result = await sut.DynamicContents("blog").GetAsync();
5353

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// ==========================================================================
2+
// Squidex Headless CMS
3+
// ==========================================================================
4+
// Copyright (c) Squidex UG (haftungsbeschraenkt)
5+
// All rights reserved. Licensed under the MIT license.
6+
// ==========================================================================
7+
8+
namespace Squidex.ClientLibrary.Tests;
9+
10+
public class BearerAuthTokenTests
11+
{
12+
[Fact]
13+
public void Should_serialize_as_header()
14+
{
15+
var sut = new BearerAuthToken("MyToken");
16+
17+
var header = sut.SerializeAsHeader();
18+
Assert.Equal(("Authorization", "Bearer MyToken"), header);
19+
}
20+
21+
[Fact]
22+
public void Should_serialize_as_query()
23+
{
24+
var sut = new BearerAuthToken("MyToken");
25+
26+
var header = sut.SerializeAsQuery();
27+
Assert.Equal(("access_token", "MyToken"), header);
28+
}
29+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// ==========================================================================
2+
// Squidex Headless CMS
3+
// ==========================================================================
4+
// Copyright (c) Squidex UG (haftungsbeschraenkt)
5+
// All rights reserved. Licensed under the MIT license.
6+
// ==========================================================================
7+
8+
using Squidex.Assets.Internal;
9+
10+
namespace Squidex.ClientLibrary;
11+
12+
/// <summary>
13+
/// A ApiKey auth token.
14+
/// </summary>
15+
public sealed class ApiKeyAuthToken : AuthToken
16+
{
17+
/// <summary>
18+
/// The app name.
19+
/// </summary>
20+
public string AppName { get; }
21+
22+
/// <summary>
23+
/// The bearer token.
24+
/// </summary>
25+
public string Value { get; }
26+
27+
/// <summary>
28+
/// Initializes a new instance of the <see cref="ApiKeyAuthToken" /> class with all properties.
29+
/// </summary>
30+
/// <param name="appName">The app name.</param>
31+
/// <param name="value">The APIKey.</param>
32+
public ApiKeyAuthToken(string appName, string value)
33+
{
34+
Guard.NotNullOrEmpty(appName, nameof(appName));
35+
Guard.NotNullOrEmpty(value, nameof(value));
36+
37+
AppName = appName;
38+
39+
Value = value;
40+
}
41+
42+
/// <inheritdoc />
43+
public override (string Name, string Value) SerializeAsQuery()
44+
{
45+
return ("api_key", Uri.EscapeDataString($"{AppName}:{Value}"));
46+
}
47+
48+
/// <inheritdoc />
49+
public override (string Name, string Value) SerializeAsHeader()
50+
{
51+
return ("Authorization", $"ApiKey {AppName}:{Value}");
52+
}
53+
}

csharp/Squidex.ClientLibrary/Squidex.ClientLibrary/AuthToken.cs

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12,29 +12,17 @@ namespace Squidex.ClientLibrary;
1212
/// <summary>
1313
/// The API key for authentication.
1414
/// </summary>
15-
public sealed class AuthToken
15+
public abstract class AuthToken
1616
{
1717
/// <summary>
18-
/// Gets the header name.
18+
/// Serializes the header value.
1919
/// </summary>
20-
public string HeaderName { get; }
20+
/// <returns>The header value.</returns>
21+
public abstract (string Name, string Value) SerializeAsHeader();
2122

2223
/// <summary>
23-
/// Gets the header value.
24+
/// Serializes the query string value.
2425
/// </summary>
25-
public string HeaderValue { get; }
26-
27-
/// <summary>
28-
/// Initializes a new instance of the <see cref="AuthToken" /> class with all properties.
29-
/// </summary>
30-
/// <param name="headerName">The header name. Cannot be null or empty.</param>
31-
/// <param name="headerValue">The header value. Cannot be null or empty.</param>
32-
public AuthToken(string headerName, string headerValue)
33-
{
34-
Guard.NotNullOrEmpty(headerName, nameof(headerName));
35-
Guard.NotNullOrEmpty(headerValue, nameof(headerValue));
36-
37-
HeaderName = headerName;
38-
HeaderValue = headerValue;
39-
}
26+
/// <returns>The query string value.</returns>
27+
public abstract (string Name, string Value) SerializeAsQuery();
4028
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// ==========================================================================
2+
// Squidex Headless CMS
3+
// ==========================================================================
4+
// Copyright (c) Squidex UG (haftungsbeschraenkt)
5+
// All rights reserved. Licensed under the MIT license.
6+
// ==========================================================================
7+
8+
using Squidex.Assets.Internal;
9+
10+
namespace Squidex.ClientLibrary;
11+
12+
/// <summary>
13+
/// A bearer auth token.
14+
/// </summary>
15+
public sealed class BearerAuthToken : AuthToken
16+
{
17+
/// <summary>
18+
/// The bearer token.
19+
/// </summary>
20+
public string Value { get; }
21+
22+
/// <summary>
23+
/// Initializes a new instance of the <see cref="BearerAuthToken" /> class with all properties.
24+
/// </summary>
25+
/// <param name="value">The token.</param>
26+
public BearerAuthToken(string value)
27+
{
28+
Guard.NotNullOrEmpty(value, nameof(value));
29+
30+
Value = value;
31+
}
32+
33+
/// <inheritdoc />
34+
public override (string Name, string Value) SerializeAsHeader()
35+
{
36+
return ("Authorization", $"Bearer {Value}");
37+
}
38+
39+
/// <inheritdoc />
40+
public override (string Name, string Value) SerializeAsQuery()
41+
{
42+
return ("access_token", Value);
43+
}
44+
}

csharp/Squidex.ClientLibrary/Squidex.ClientLibrary/Configuration/ApiKeyAuthenticator.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@ namespace Squidex.ClientLibrary.Configuration;
1010
internal sealed class ApiKeyAuthenticator(string appName, string apiKey) : IAuthenticator
1111
{
1212
private readonly Task<AuthToken> token =
13-
Task.FromResult(
14-
new AuthToken("Authorization", $"ApiKey {appName}:{apiKey}"));
13+
Task.FromResult<AuthToken>(new ApiKeyAuthToken(appName, apiKey));
1514

1615
public Task<AuthToken> GetAuthTokenAsync(string appName, CancellationToken ct)
1716
{

csharp/Squidex.ClientLibrary/Squidex.ClientLibrary/Configuration/Authenticator.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ public async Task<AuthToken> GetAuthTokenAsync(string appName,
8585
#endif
8686
var jsonToken = JToken.Parse(jsonString);
8787

88-
return new AuthToken("Authorization", $"Bearer {jsonToken["access_token"]!}");
88+
return new BearerAuthToken($"{jsonToken["access_token"]!}");
8989
}
9090

9191
private void StorePreviousAttempt(string clientId, string clientSecret, Exception exception)

0 commit comments

Comments
 (0)