Skip to content

Commit dd1c560

Browse files
Add Streamlabs provider (#553)
* Add streamlabs provider * Update src/AspNet.Security.OAuth.Streamlabs/StreamlabsAuthenticationConstants.cs Thanks for the correction. Co-authored-by: Martin Costello <[email protected]> * Redundant GetData removed. * Missing tests added. Co-authored-by: Martin Costello <[email protected]>
1 parent 81b7097 commit dd1c560

10 files changed

+403
-0
lines changed

AspNet.Security.OAuth.Providers.sln

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AspNet.Security.OAuth.Line"
212212
EndProject
213213
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AspNet.Security.OAuth.Moodle", "src\AspNet.Security.OAuth.Moodle\AspNet.Security.OAuth.Moodle.csproj", "{1745B11F-F700-4604-B61F-54B962A6BE9A}"
214214
EndProject
215+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AspNet.Security.OAuth.Streamlabs", "src\AspNet.Security.OAuth.Streamlabs\AspNet.Security.OAuth.Streamlabs.csproj", "{514D2D1E-E72F-4998-9DF3-D841F399AB37}"
216+
EndProject
215217
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AspNet.Security.OAuth.Keycloak", "src\AspNet.Security.OAuth.Keycloak\AspNet.Security.OAuth.Keycloak.csproj", "{01C2AC98-B615-49F8-80A5-475A2B75A8FD}"
216218
EndProject
217219
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AspNet.Security.OAuth.WorkWeixin", "src\AspNet.Security.OAuth.WorkWeixin\AspNet.Security.OAuth.WorkWeixin.csproj", "{C40ED377-E365-45FB-8B42-27BE82CC7BE3}"
@@ -512,6 +514,10 @@ Global
512514
{1745B11F-F700-4604-B61F-54B962A6BE9A}.Debug|Any CPU.Build.0 = Debug|Any CPU
513515
{1745B11F-F700-4604-B61F-54B962A6BE9A}.Release|Any CPU.ActiveCfg = Release|Any CPU
514516
{1745B11F-F700-4604-B61F-54B962A6BE9A}.Release|Any CPU.Build.0 = Release|Any CPU
517+
{514D2D1E-E72F-4998-9DF3-D841F399AB37}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
518+
{514D2D1E-E72F-4998-9DF3-D841F399AB37}.Debug|Any CPU.Build.0 = Debug|Any CPU
519+
{514D2D1E-E72F-4998-9DF3-D841F399AB37}.Release|Any CPU.ActiveCfg = Release|Any CPU
520+
{514D2D1E-E72F-4998-9DF3-D841F399AB37}.Release|Any CPU.Build.0 = Release|Any CPU
515521
{DF2786DF-234D-4A8C-B166-0B8F8B7D527B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
516522
{DF2786DF-234D-4A8C-B166-0B8F8B7D527B}.Debug|Any CPU.Build.0 = Debug|Any CPU
517523
{DF2786DF-234D-4A8C-B166-0B8F8B7D527B}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -607,6 +613,7 @@ Global
607613
{61AB67B0-0F4A-47A2-A4D8-9738AA34C468} = {C1352FD3-AE8B-43EE-B45B-F6E0B3FBAC6D}
608614
{6A2FEBAB-2372-4043-BD37-B2E94887BA9B} = {C1352FD3-AE8B-43EE-B45B-F6E0B3FBAC6D}
609615
{1745B11F-F700-4604-B61F-54B962A6BE9A} = {C1352FD3-AE8B-43EE-B45B-F6E0B3FBAC6D}
616+
{514D2D1E-E72F-4998-9DF3-D841F399AB37} = {C1352FD3-AE8B-43EE-B45B-F6E0B3FBAC6D}
610617
{DF2786DF-234D-4A8C-B166-0B8F8B7D527B} = {C1352FD3-AE8B-43EE-B45B-F6E0B3FBAC6D}
611618
{01C2AC98-B615-49F8-80A5-475A2B75A8FD} = {C1352FD3-AE8B-43EE-B45B-F6E0B3FBAC6D}
612619
{C40ED377-E365-45FB-8B42-27BE82CC7BE3} = {C1352FD3-AE8B-43EE-B45B-F6E0B3FBAC6D}

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ If a provider you're looking for does not exist, consider making a PR to add one
168168
| Spotify | [![NuGet](https://buildstats.info/nuget/AspNet.Security.OAuth.Spotify?includePreReleases=false)](https://www.nuget.org/packages/AspNet.Security.OAuth.Spotify/ "Download AspNet.Security.OAuth.Spotify from NuGet.org") | [![MyGet](https://buildstats.info/myget/aspnet-contrib/AspNet.Security.OAuth.Spotify?includePreReleases=true)](https://www.myget.org/feed/aspnet-contrib/package/nuget/AspNet.Security.OAuth.Spotify "Download AspNet.Security.OAuth.Spotify from MyGet.org") | [Documentation](https://developer.spotify.com/documentation/general/guides/authorization-guide/ "Spotify developer documentation") |
169169
| Stack Exchange | [![NuGet](https://buildstats.info/nuget/AspNet.Security.OAuth.StackExchange?includePreReleases=false)](https://www.nuget.org/packages/AspNet.Security.OAuth.StackExchange/ "Download AspNet.Security.OAuth.StackExchange from NuGet.org") | [![MyGet](https://buildstats.info/myget/aspnet-contrib/AspNet.Security.OAuth.StackExchange?includePreReleases=true)](https://www.myget.org/feed/aspnet-contrib/package/nuget/AspNet.Security.OAuth.StackExchange "Download AspNet.Security.OAuth.StackExchange from MyGet.org") | [Documentation](https://api.stackexchange.com/docs/authentication "Stack Exchange developer documentation") |
170170
| Strava | [![NuGet](https://buildstats.info/nuget/AspNet.Security.OAuth.Strava?includePreReleases=false)](https://www.nuget.org/packages/AspNet.Security.OAuth.Strava/ "Download AspNet.Security.OAuth.Strava from NuGet.org") | [![MyGet](https://buildstats.info/myget/aspnet-contrib/AspNet.Security.OAuth.Strava?includePreReleases=true)](https://www.myget.org/feed/aspnet-contrib/package/nuget/AspNet.Security.OAuth.Strava "Download AspNet.Security.OAuth.Strava from MyGet.org") | [Documentation](https://developers.strava.com/docs/authentication/ "Strava developer documentation") |
171+
| Streamlabs | [![NuGet](https://buildstats.info/nuget/AspNet.Security.OAuth.Streamlabs?includePreReleases=false)](https://www.nuget.org/packages/AspNet.Security.OAuth.Streamlabs/ "Download AspNet.Security.OAuth.Streamlabs from NuGet.org") | [![MyGet](https://buildstats.info/myget/aspnet-contrib/AspNet.Security.OAuth.Streamlabs?includePreReleases=true)](https://www.myget.org/feed/aspnet-contrib/package/nuget/AspNet.Security.OAuth.Streamlabs "Download AspNet.Security.OAuth.Streamlabs from MyGet.org") | [Documentation](https://dev.streamlabs.com/reference#authorize "Streamlabs developer documentation") |
171172
| SuperOffice | [![NuGet](https://buildstats.info/nuget/AspNet.Security.OAuth.SuperOffice?includePreReleases=false)](https://www.nuget.org/packages/AspNet.Security.OAuth.SuperOffice/ "Download AspNet.Security.OAuth.SuperOffice from NuGet.org") | [![MyGet](https://buildstats.info/myget/aspnet-contrib/AspNet.Security.OAuth.SuperOffice?includePreReleases=true)](https://www.myget.org/feed/aspnet-contrib/package/nuget/AspNet.Security.OAuth.SuperOffice "Download AspNet.Security.OAuth.SuperOffice from MyGet.org") | [Documentation](https://community.superoffice.com/en/developer/create-apps/concepts/authentication/ "SuperOffice developer documentation") |
172173
| Trakt | [![NuGet](https://buildstats.info/nuget/AspNet.Security.OAuth.Trakt?includePreReleases=false)](https://www.nuget.org/packages/AspNet.Security.OAuth.Trakt/ "Download AspNet.Security.OAuth.Trakt from NuGet.org") | [![MyGet](https://buildstats.info/myget/aspnet-contrib/AspNet.Security.OAuth.Trakt?includePreReleases=true)](https://www.myget.org/feed/aspnet-contrib/package/nuget/AspNet.Security.OAuth.Trakt "Download AspNet.Security.OAuth.Trakt from MyGet.org") | [Documentation](https://trakt.docs.apiary.io/ "Trakt developer documentation") |
173174
| Twitch | [![NuGet](https://buildstats.info/nuget/AspNet.Security.OAuth.Twitch?includePreReleases=false)](https://www.nuget.org/packages/AspNet.Security.OAuth.Twitch/ "Download AspNet.Security.OAuth.Twitch from NuGet.org") | [![MyGet](https://buildstats.info/myget/aspnet-contrib/AspNet.Security.OAuth.Twitch?includePreReleases=true)](https://www.myget.org/feed/aspnet-contrib/package/nuget/AspNet.Security.OAuth.Twitch "Download AspNet.Security.OAuth.Twitch from MyGet.org") | [Documentation](https://dev.twitch.tv/docs/authentication/ "Twitch developer documentation") |
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net5.0</TargetFramework>
5+
</PropertyGroup>
6+
7+
8+
<PropertyGroup>
9+
<Description>ASP.NET Core security middleware enabling Streamlabs authentication.</Description>
10+
<Authors>Sertay Kabuk</Authors>
11+
<PackageTags>aspnetcore;authentication;oauth;security;streamlabs</PackageTags>
12+
</PropertyGroup>
13+
14+
<ItemGroup>
15+
<FrameworkReference Include="Microsoft.AspNetCore.App" />
16+
<PackageReference Include="JetBrains.Annotations" PrivateAssets="All" />
17+
</ItemGroup>
18+
19+
</Project>
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
3+
* See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers
4+
* for more information concerning the license and the contributors participating to this project.
5+
*/
6+
7+
namespace AspNet.Security.OAuth.Streamlabs
8+
{
9+
/// <summary>
10+
/// Contains constants specific to the <see cref="StreamlabsAuthenticationHandler"/>.
11+
/// </summary>
12+
public static class StreamlabsAuthenticationConstants
13+
{
14+
public static class Claims
15+
{
16+
public const string DisplayName = "urn:streamlabs:displayname";
17+
public const string FacebookId = "urn:streamlabs:facebookid";
18+
public const string FacebookName = "urn:streamlabs:facebookname";
19+
public const string Primary = "urn:streamlabs:primary";
20+
public const string Thumbnail = "urn:streamlabs:thumbnail";
21+
public const string TwitchDisplayName = "urn:streamlabs:twitchdisplayname";
22+
public const string TwitchIconUrl = "urn:streamlabs:twitchiconurl";
23+
public const string TwitchId = "urn:streamlabs:twitchid";
24+
public const string TwitchName = "urn:streamlabs:twitchname";
25+
public const string YouTubeId = "urn:streamlabs:youtubeid";
26+
public const string YouTubeTitle = "urn:streamlabs:youtubetitle";
27+
}
28+
}
29+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
3+
* See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers
4+
* for more information concerning the license and the contributors participating to this project.
5+
*/
6+
7+
using Microsoft.AspNetCore.Authentication;
8+
using Microsoft.AspNetCore.Authentication.OAuth;
9+
10+
namespace AspNet.Security.OAuth.Streamlabs
11+
{
12+
/// <summary>
13+
/// Default values used by the Streamlabs authentication middleware.
14+
/// </summary>
15+
public static class StreamlabsAuthenticationDefaults
16+
{
17+
/// <summary>
18+
/// Default value for <see cref="AuthenticationScheme.Name"/>.
19+
/// </summary>
20+
public const string AuthenticationScheme = "Streamlabs";
21+
22+
/// <summary>
23+
/// Default value for <see cref="AuthenticationScheme.DisplayName"/>.
24+
/// </summary>
25+
public const string DisplayName = "Streamlabs";
26+
27+
/// <summary>
28+
/// Default value for <see cref="AuthenticationSchemeOptions.ClaimsIssuer"/>.
29+
/// </summary>
30+
public const string Issuer = "Streamlabs";
31+
32+
/// <summary>
33+
/// Default value for <see cref="RemoteAuthenticationOptions.CallbackPath"/>.
34+
/// </summary>
35+
public const string CallbackPath = "/signin-streamlabs";
36+
37+
/// <summary>
38+
/// Default value for <see cref="OAuthOptions.AuthorizationEndpoint"/>.
39+
/// </summary>
40+
public const string AuthorizationEndPoint = "https://streamlabs.com/api/v1.0/authorize";
41+
42+
/// <summary>
43+
/// Default value for <see cref="OAuthOptions.TokenEndpoint"/>.
44+
/// </summary>
45+
public const string TokenEndpoint = "https://streamlabs.com/api/v1.0/token";
46+
47+
/// <summary>
48+
/// Default value for <see cref="OAuthOptions.UserInformationEndpoint"/>.
49+
/// </summary>
50+
public const string UserInformationEndpoint = "https://streamlabs.com/api/v1.0/user";
51+
}
52+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
3+
* See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers
4+
* for more information concerning the license and the contributors participating to this project.
5+
*/
6+
7+
using System;
8+
using AspNet.Security.OAuth.Streamlabs;
9+
using JetBrains.Annotations;
10+
using Microsoft.AspNetCore.Authentication;
11+
12+
namespace Microsoft.Extensions.DependencyInjection
13+
{
14+
/// <summary>
15+
/// Extension methods to add Streamlabs authentication capabilities to an HTTP application pipeline.
16+
/// </summary>
17+
public static class StreamlabsAuthenticationExtensions
18+
{
19+
/// <summary>
20+
/// Adds <see cref="StreamlabsAuthenticationHandler"/> to the specified
21+
/// <see cref="AuthenticationBuilder"/>, which enables Streamlabs authentication capabilities.
22+
/// </summary>
23+
/// <param name="builder">The authentication builder.</param>
24+
/// <returns>A reference to this instance after the operation has completed.</returns>
25+
public static AuthenticationBuilder AddStreamlabs([NotNull] this AuthenticationBuilder builder)
26+
{
27+
return builder.AddStreamlabs(StreamlabsAuthenticationDefaults.AuthenticationScheme, options => { });
28+
}
29+
30+
/// <summary>
31+
/// Adds <see cref="StreamlabsAuthenticationHandler"/> to the specified
32+
/// <see cref="AuthenticationBuilder"/>, which enables Streamlabs authentication capabilities.
33+
/// </summary>
34+
/// <param name="builder">The authentication builder.</param>
35+
/// <param name="configuration">The delegate used to configure the OpenID 2.0 options.</param>
36+
/// <returns>A reference to this instance after the operation has completed.</returns>
37+
public static AuthenticationBuilder AddStreamlabs(
38+
[NotNull] this AuthenticationBuilder builder,
39+
[NotNull] Action<StreamlabsAuthenticationOptions> configuration)
40+
{
41+
return builder.AddStreamlabs(StreamlabsAuthenticationDefaults.AuthenticationScheme, configuration);
42+
}
43+
44+
/// <summary>
45+
/// Adds <see cref="StreamlabsAuthenticationHandler"/> to the specified
46+
/// <see cref="AuthenticationBuilder"/>, which enables Streamlabs authentication capabilities.
47+
/// </summary>
48+
/// <param name="builder">The authentication builder.</param>
49+
/// <param name="scheme">The authentication scheme associated with this instance.</param>
50+
/// <param name="configuration">The delegate used to configure the Streamlabs options.</param>
51+
/// <returns>The <see cref="AuthenticationBuilder"/>.</returns>
52+
public static AuthenticationBuilder AddStreamlabs(
53+
[NotNull] this AuthenticationBuilder builder,
54+
[NotNull] string scheme,
55+
[NotNull] Action<StreamlabsAuthenticationOptions> configuration)
56+
{
57+
return builder.AddStreamlabs(scheme, StreamlabsAuthenticationDefaults.DisplayName, configuration);
58+
}
59+
60+
/// <summary>
61+
/// Adds <see cref="StreamlabsAuthenticationHandler"/> to the specified
62+
/// <see cref="AuthenticationBuilder"/>, which enables Streamlabs authentication capabilities.
63+
/// </summary>
64+
/// <param name="builder">The authentication builder.</param>
65+
/// <param name="scheme">The authentication scheme associated with this instance.</param>
66+
/// <param name="caption">The optional display name associated with this instance.</param>
67+
/// <param name="configuration">The delegate used to configure the Streamlabs options.</param>
68+
/// <returns>The <see cref="AuthenticationBuilder"/>.</returns>
69+
public static AuthenticationBuilder AddStreamlabs(
70+
[NotNull] this AuthenticationBuilder builder,
71+
[NotNull] string scheme,
72+
[CanBeNull] string caption,
73+
[NotNull] Action<StreamlabsAuthenticationOptions> configuration)
74+
{
75+
return builder.AddOAuth<StreamlabsAuthenticationOptions, StreamlabsAuthenticationHandler>(scheme, caption, configuration);
76+
}
77+
}
78+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/*
2+
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
3+
* See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers
4+
* for more information concerning the license and the contributors participating to this project.
5+
*/
6+
7+
using System.Collections.Generic;
8+
using System.Net.Http;
9+
using System.Net.Http.Headers;
10+
using System.Security.Claims;
11+
using System.Text.Encodings.Web;
12+
using System.Text.Json;
13+
using System.Threading.Tasks;
14+
using JetBrains.Annotations;
15+
using Microsoft.AspNetCore.Authentication;
16+
using Microsoft.AspNetCore.Authentication.OAuth;
17+
using Microsoft.AspNetCore.WebUtilities;
18+
using Microsoft.Extensions.Logging;
19+
using Microsoft.Extensions.Options;
20+
21+
namespace AspNet.Security.OAuth.Streamlabs
22+
{
23+
public class StreamlabsAuthenticationHandler : OAuthHandler<StreamlabsAuthenticationOptions>
24+
{
25+
public StreamlabsAuthenticationHandler(
26+
[NotNull] IOptionsMonitor<StreamlabsAuthenticationOptions> options,
27+
[NotNull] ILoggerFactory logger,
28+
[NotNull] UrlEncoder encoder,
29+
[NotNull] ISystemClock clock)
30+
: base(options, logger, encoder, clock)
31+
{
32+
}
33+
34+
protected override string BuildChallengeUrl([NotNull] AuthenticationProperties properties, [NotNull] string redirectUri)
35+
=> QueryHelpers.AddQueryString(Options.AuthorizationEndpoint, new Dictionary<string, string?>
36+
{
37+
["client_id"] = Options.ClientId,
38+
["scope"] = FormatScope(),
39+
["response_type"] = "code",
40+
["redirect_uri"] = redirectUri,
41+
["state"] = Options.StateDataFormat.Protect(properties)
42+
});
43+
44+
protected override async Task<AuthenticationTicket> CreateTicketAsync(
45+
[NotNull] ClaimsIdentity identity,
46+
[NotNull] AuthenticationProperties properties,
47+
[NotNull] OAuthTokenResponse tokens)
48+
{
49+
using var request = new HttpRequestMessage(HttpMethod.Get, Options.UserInformationEndpoint);
50+
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
51+
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", tokens.AccessToken);
52+
53+
using var response = await Backchannel.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, Context.RequestAborted);
54+
if (!response.IsSuccessStatusCode)
55+
{
56+
Logger.LogError("An error occurred while retrieving the user profile: the remote server " +
57+
"returned a {Status} response with the following payload: {Headers} {Body}.",
58+
/* Status: */ response.StatusCode,
59+
/* Headers: */ response.Headers.ToString(),
60+
/* Body: */ await response.Content.ReadAsStringAsync(Context.RequestAborted));
61+
62+
throw new HttpRequestException("An error occurred while retrieving the user profile.");
63+
}
64+
65+
using var payload = JsonDocument.Parse(await response.Content.ReadAsStringAsync(Context.RequestAborted));
66+
67+
var principal = new ClaimsPrincipal(identity);
68+
var context = new OAuthCreatingTicketContext(principal, properties, Context, Scheme, Options, Backchannel, tokens, payload.RootElement);
69+
context.RunClaimActions();
70+
71+
await Options.Events.CreatingTicket(context);
72+
return new AuthenticationTicket(context.Principal!, context.Properties, Scheme.Name);
73+
}
74+
}
75+
}

0 commit comments

Comments
 (0)