diff --git a/src/Tgstation.Server.Host/Authority/IUserAuthority.cs b/src/Tgstation.Server.Host/Authority/IUserAuthority.cs
index b0a67681cd..4b67a3e55b 100644
--- a/src/Tgstation.Server.Host/Authority/IUserAuthority.cs
+++ b/src/Tgstation.Server.Host/Authority/IUserAuthority.cs
@@ -6,6 +6,7 @@ using Tgstation.Server.Api.Models;
using Tgstation.Server.Api.Models.Request;
using Tgstation.Server.Api.Rights;
using Tgstation.Server.Host.Authority.Core;
+using Tgstation.Server.Host.GraphQL.Types.OAuth;
using Tgstation.Server.Host.Models;
using Tgstation.Server.Host.Security;
@@ -40,8 +41,8 @@ namespace Tgstation.Server.Host.Authority
///
/// The of the .
/// The for the operation.
- /// A resulting in an of .
- ValueTask> OAuthConnections(long userId, CancellationToken cancellationToken);
+ /// A resulting in an of .
+ ValueTask> OAuthConnections(long userId, CancellationToken cancellationToken);
///
/// Gets all registered s.
diff --git a/src/Tgstation.Server.Host/Authority/UserAuthority.cs b/src/Tgstation.Server.Host/Authority/UserAuthority.cs
index 753a180d30..686eb10f47 100644
--- a/src/Tgstation.Server.Host/Authority/UserAuthority.cs
+++ b/src/Tgstation.Server.Host/Authority/UserAuthority.cs
@@ -102,7 +102,7 @@ namespace Tgstation.Server.Host.Authority
/// The for the operation.
/// A resulting in a of the requested s.
[DataLoader]
- public static async ValueTask> GetOAuthConnections(
+ public static async ValueTask> GetOAuthConnections(
IReadOnlyList userIds,
IDatabaseContext databaseContext,
CancellationToken cancellationToken)
@@ -118,7 +118,7 @@ namespace Tgstation.Server.Host.Authority
return list.ToLookup(
oauthConnection => oauthConnection.UserId,
- x => new GraphQL.Types.OAuthConnection(x.ExternalUserId!, x.Provider));
+ x => new GraphQL.Types.OAuth.OAuthConnection(x.ExternalUserId!, x.Provider));
}
///
@@ -285,8 +285,8 @@ namespace Tgstation.Server.Host.Authority
=> Queryable(includeJoins, false);
///
- public async ValueTask> OAuthConnections(long userId, CancellationToken cancellationToken)
- => new AuthorityResponse(
+ public async ValueTask> OAuthConnections(long userId, CancellationToken cancellationToken)
+ => new AuthorityResponse(
await oAuthConnectionsDataLoader.LoadRequiredAsync(userId, cancellationToken));
///
diff --git a/src/Tgstation.Server.Host/Core/Application.cs b/src/Tgstation.Server.Host/Core/Application.cs
index aa7753c05c..3a310a7ec9 100644
--- a/src/Tgstation.Server.Host/Core/Application.cs
+++ b/src/Tgstation.Server.Host/Core/Application.cs
@@ -57,10 +57,10 @@ using Tgstation.Server.Host.Controllers.Results;
using Tgstation.Server.Host.Database;
using Tgstation.Server.Host.Extensions;
using Tgstation.Server.Host.GraphQL;
+using Tgstation.Server.Host.GraphQL.Interceptors;
+using Tgstation.Server.Host.GraphQL.Scalars;
using Tgstation.Server.Host.GraphQL.Subscriptions;
using Tgstation.Server.Host.GraphQL.Types;
-using Tgstation.Server.Host.GraphQL.Types.Interceptors;
-using Tgstation.Server.Host.GraphQL.Types.Scalars;
using Tgstation.Server.Host.IO;
using Tgstation.Server.Host.Jobs;
using Tgstation.Server.Host.Properties;
diff --git a/src/Tgstation.Server.Host/GraphQL/Types/Interceptors/RightsTypeInterceptor.cs b/src/Tgstation.Server.Host/GraphQL/Interceptors/RightsTypeInterceptor.cs
similarity index 97%
rename from src/Tgstation.Server.Host/GraphQL/Types/Interceptors/RightsTypeInterceptor.cs
rename to src/Tgstation.Server.Host/GraphQL/Interceptors/RightsTypeInterceptor.cs
index 538c32b3ad..5fea9058e3 100644
--- a/src/Tgstation.Server.Host/GraphQL/Types/Interceptors/RightsTypeInterceptor.cs
+++ b/src/Tgstation.Server.Host/GraphQL/Interceptors/RightsTypeInterceptor.cs
@@ -6,10 +6,10 @@ using System.Reflection;
using HotChocolate.Configuration;
using HotChocolate.Types;
using HotChocolate.Types.Descriptors.Definitions;
-
using Tgstation.Server.Api.Rights;
+using Tgstation.Server.Host.GraphQL.Types;
-namespace Tgstation.Server.Host.GraphQL.Types.Interceptors
+namespace Tgstation.Server.Host.GraphQL.Interceptors
{
///
/// Fixes the names used for the default flags types in API rights.
diff --git a/src/Tgstation.Server.Host/GraphQL/Mutations/Payloads/LoginPayload.cs b/src/Tgstation.Server.Host/GraphQL/Mutations/Payloads/LoginPayload.cs
index 8d5cd5e683..407ebab3b7 100644
--- a/src/Tgstation.Server.Host/GraphQL/Mutations/Payloads/LoginPayload.cs
+++ b/src/Tgstation.Server.Host/GraphQL/Mutations/Payloads/LoginPayload.cs
@@ -1,6 +1,6 @@
using HotChocolate;
using Tgstation.Server.Api.Models.Response;
-using Tgstation.Server.Host.GraphQL.Types.Scalars;
+using Tgstation.Server.Host.GraphQL.Scalars;
using Tgstation.Server.Host.Models;
namespace Tgstation.Server.Host.GraphQL.Mutations.Payloads
diff --git a/src/Tgstation.Server.Host/GraphQL/Mutations/UserMutations.cs b/src/Tgstation.Server.Host/GraphQL/Mutations/UserMutations.cs
index 5c51fd8bc3..77fc7e3445 100644
--- a/src/Tgstation.Server.Host/GraphQL/Mutations/UserMutations.cs
+++ b/src/Tgstation.Server.Host/GraphQL/Mutations/UserMutations.cs
@@ -13,6 +13,7 @@ using Tgstation.Server.Api.Rights;
using Tgstation.Server.Host.Authority;
using Tgstation.Server.Host.GraphQL.Mutations.Payloads;
using Tgstation.Server.Host.GraphQL.Types;
+using Tgstation.Server.Host.GraphQL.Types.OAuth;
using Tgstation.Server.Host.Models.Transformers;
using Tgstation.Server.Host.Security;
diff --git a/src/Tgstation.Server.Host/GraphQL/Types/Scalars/JwtType.cs b/src/Tgstation.Server.Host/GraphQL/Scalars/JwtType.cs
similarity index 94%
rename from src/Tgstation.Server.Host/GraphQL/Types/Scalars/JwtType.cs
rename to src/Tgstation.Server.Host/GraphQL/Scalars/JwtType.cs
index 47f10ccde3..170a744a42 100644
--- a/src/Tgstation.Server.Host/GraphQL/Types/Scalars/JwtType.cs
+++ b/src/Tgstation.Server.Host/GraphQL/Scalars/JwtType.cs
@@ -3,7 +3,7 @@
using HotChocolate.Language;
using HotChocolate.Types;
-namespace Tgstation.Server.Host.GraphQL.Types.Scalars
+namespace Tgstation.Server.Host.GraphQL.Scalars
{
///
/// A for encoded JSON Web Tokens.
diff --git a/src/Tgstation.Server.Host/GraphQL/Types/Scalars/SemverType.cs b/src/Tgstation.Server.Host/GraphQL/Scalars/SemverType.cs
similarity index 97%
rename from src/Tgstation.Server.Host/GraphQL/Types/Scalars/SemverType.cs
rename to src/Tgstation.Server.Host/GraphQL/Scalars/SemverType.cs
index dce31b4751..de8c1e530a 100644
--- a/src/Tgstation.Server.Host/GraphQL/Types/Scalars/SemverType.cs
+++ b/src/Tgstation.Server.Host/GraphQL/Scalars/SemverType.cs
@@ -2,10 +2,9 @@
using HotChocolate.Language;
using HotChocolate.Types;
-
using Tgstation.Server.Common.Extensions;
-namespace Tgstation.Server.Host.GraphQL.Types.Scalars
+namespace Tgstation.Server.Host.GraphQL.Scalars
{
///
/// A for semantic s.
diff --git a/src/Tgstation.Server.Host/GraphQL/Types/GatewayInformation.cs b/src/Tgstation.Server.Host/GraphQL/Types/GatewayInformation.cs
index 727e38c5f1..9a1aee31cf 100644
--- a/src/Tgstation.Server.Host/GraphQL/Types/GatewayInformation.cs
+++ b/src/Tgstation.Server.Host/GraphQL/Types/GatewayInformation.cs
@@ -10,6 +10,7 @@ using Tgstation.Server.Api.Models;
using Tgstation.Server.Api.Rights;
using Tgstation.Server.Host.Components.Interop;
using Tgstation.Server.Host.Configuration;
+using Tgstation.Server.Host.GraphQL.Types.OAuth;
using Tgstation.Server.Host.Properties;
using Tgstation.Server.Host.Security;
using Tgstation.Server.Host.Security.OAuth;
@@ -148,12 +149,12 @@ namespace Tgstation.Server.Host.GraphQL.Types
/// Gets the information needed to perform open authentication with the .
///
/// The to use.
- /// A map of enabled s to their .
- public IReadOnlyDictionary OAuthProviderInfos(
+ /// A map of enabled s to their .
+ public OAuthProviderInfos OAuthProviderInfos(
[Service] IOAuthProviders oAuthProviders)
{
ArgumentNullException.ThrowIfNull(oAuthProviders);
- return oAuthProviders.ProviderInfos();
+ return new OAuthProviderInfos(oAuthProviders);
}
}
}
diff --git a/src/Tgstation.Server.Host/GraphQL/Types/OAuth/BasicOAuthProviderInfo.cs b/src/Tgstation.Server.Host/GraphQL/Types/OAuth/BasicOAuthProviderInfo.cs
new file mode 100644
index 0000000000..f503d7adc8
--- /dev/null
+++ b/src/Tgstation.Server.Host/GraphQL/Types/OAuth/BasicOAuthProviderInfo.cs
@@ -0,0 +1,28 @@
+using System;
+
+using Tgstation.Server.Api.Models;
+
+namespace Tgstation.Server.Host.GraphQL.Types.OAuth
+{
+ ///
+ /// Basic OAuth provider info.
+ ///
+ public class BasicOAuthProviderInfo
+ {
+ ///
+ /// The client ID.
+ ///
+ public string ClientID { get; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The to build from.
+ public BasicOAuthProviderInfo(OAuthProviderInfo providerInfo)
+ {
+ ArgumentNullException.ThrowIfNull(providerInfo);
+
+ ClientID = providerInfo.ClientId ?? throw new InvalidOperationException("ClientID not set!");
+ }
+ }
+}
diff --git a/src/Tgstation.Server.Host/GraphQL/Types/OAuth/FullOAuthProviderInfo.cs b/src/Tgstation.Server.Host/GraphQL/Types/OAuth/FullOAuthProviderInfo.cs
new file mode 100644
index 0000000000..cd750f665b
--- /dev/null
+++ b/src/Tgstation.Server.Host/GraphQL/Types/OAuth/FullOAuthProviderInfo.cs
@@ -0,0 +1,29 @@
+using System;
+
+using Tgstation.Server.Api.Models;
+
+namespace Tgstation.Server.Host.GraphQL.Types.OAuth
+{
+ ///
+ /// OAuth provider info with a and .
+ ///
+ public sealed class FullOAuthProviderInfo : RedirectOAuthProviderInfo
+ {
+ ///
+ /// The remote service URL.
+ ///
+ public Uri ServerUrl { get; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The to build from.
+ public FullOAuthProviderInfo(OAuthProviderInfo providerInfo)
+ : base(providerInfo)
+ {
+ ArgumentNullException.ThrowIfNull(providerInfo);
+
+ ServerUrl = providerInfo.ServerUrl ?? throw new InvalidOperationException("Missing OAuthProviderInfo ServerUrl!");
+ }
+ }
+}
diff --git a/src/Tgstation.Server.Host/GraphQL/Types/OAuthConnection.cs b/src/Tgstation.Server.Host/GraphQL/Types/OAuth/OAuthConnection.cs
similarity index 94%
rename from src/Tgstation.Server.Host/GraphQL/Types/OAuthConnection.cs
rename to src/Tgstation.Server.Host/GraphQL/Types/OAuth/OAuthConnection.cs
index 7b0732fe92..cae66dec1a 100644
--- a/src/Tgstation.Server.Host/GraphQL/Types/OAuthConnection.cs
+++ b/src/Tgstation.Server.Host/GraphQL/Types/OAuth/OAuthConnection.cs
@@ -1,8 +1,7 @@
using System;
-
using Tgstation.Server.Api.Models;
-namespace Tgstation.Server.Host.GraphQL.Types
+namespace Tgstation.Server.Host.GraphQL.Types.OAuth
{
///
/// Represents a valid OAuth connection.
diff --git a/src/Tgstation.Server.Host/GraphQL/Types/OAuth/OAuthProviderInfos.cs b/src/Tgstation.Server.Host/GraphQL/Types/OAuth/OAuthProviderInfos.cs
new file mode 100644
index 0000000000..da9bffe4b3
--- /dev/null
+++ b/src/Tgstation.Server.Host/GraphQL/Types/OAuth/OAuthProviderInfos.cs
@@ -0,0 +1,66 @@
+using System;
+
+using Tgstation.Server.Api.Models;
+using Tgstation.Server.Host.Security.OAuth;
+
+namespace Tgstation.Server.Host.GraphQL.Types.OAuth
+{
+ ///
+ /// Description of configured OAuth services.
+ ///
+ public sealed class OAuthProviderInfos
+ {
+ ///
+ /// https://discord.com.
+ ///
+ public BasicOAuthProviderInfo? Discord { get; }
+
+ ///
+ /// https://github.com.
+ ///
+ public RedirectOAuthProviderInfo? GitHub { get; }
+
+ ///
+ /// https://tgstation13.org.
+ ///
+ public RedirectOAuthProviderInfo? TGForums { get; }
+
+ ///
+ /// https://www.keycloak.org.
+ ///
+ public FullOAuthProviderInfo? Keycloak { get; }
+
+ ///
+ /// https://invisioncommunity.com.
+ ///
+ public FullOAuthProviderInfo? InvisionCommunity { get; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The to get data from.
+ public OAuthProviderInfos(IOAuthProviders oAuthProviders)
+ {
+ ArgumentNullException.ThrowIfNull(oAuthProviders);
+
+ var dic = oAuthProviders.ProviderInfos();
+
+ TProviderInfo? TryBuild(OAuthProvider oAuthProvider, Func contructor)
+ where TProviderInfo : BasicOAuthProviderInfo
+ {
+ if (dic.TryGetValue(oAuthProvider, out var providerInfo))
+ {
+ return contructor(providerInfo);
+ }
+
+ return null;
+ }
+
+ Discord = TryBuild(OAuthProvider.Discord, info => new BasicOAuthProviderInfo(info));
+ GitHub = TryBuild(OAuthProvider.GitHub, info => new RedirectOAuthProviderInfo(info));
+ TGForums = TryBuild(OAuthProvider.TGForums, info => new RedirectOAuthProviderInfo(info));
+ Keycloak = TryBuild(OAuthProvider.Keycloak, info => new FullOAuthProviderInfo(info));
+ InvisionCommunity = TryBuild(OAuthProvider.InvisionCommunity, info => new FullOAuthProviderInfo(info));
+ }
+ }
+}
diff --git a/src/Tgstation.Server.Host/GraphQL/Types/OAuth/RedirectOAuthProviderInfo.cs b/src/Tgstation.Server.Host/GraphQL/Types/OAuth/RedirectOAuthProviderInfo.cs
new file mode 100644
index 0000000000..ec0b00f6a0
--- /dev/null
+++ b/src/Tgstation.Server.Host/GraphQL/Types/OAuth/RedirectOAuthProviderInfo.cs
@@ -0,0 +1,27 @@
+using System;
+
+using Tgstation.Server.Api.Models;
+
+namespace Tgstation.Server.Host.GraphQL.Types.OAuth
+{
+ ///
+ /// OAuth provider info with a .
+ ///
+ public class RedirectOAuthProviderInfo : BasicOAuthProviderInfo
+ {
+ ///
+ /// The authentication server URL.
+ ///
+ public Uri RedirectUri { get; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The to build from.
+ public RedirectOAuthProviderInfo(OAuthProviderInfo providerInfo)
+ : base(providerInfo)
+ {
+ RedirectUri = providerInfo!.RedirectUri ?? throw new InvalidOperationException("RedirectUri not set!");
+ }
+ }
+}
diff --git a/src/Tgstation.Server.Host/GraphQL/Types/OAuth/ServerUrlOAuthProviderInfo.cs b/src/Tgstation.Server.Host/GraphQL/Types/OAuth/ServerUrlOAuthProviderInfo.cs
new file mode 100644
index 0000000000..2add1c2bae
--- /dev/null
+++ b/src/Tgstation.Server.Host/GraphQL/Types/OAuth/ServerUrlOAuthProviderInfo.cs
@@ -0,0 +1,27 @@
+using System;
+
+using Tgstation.Server.Api.Models;
+
+namespace Tgstation.Server.Host.GraphQL.Types.OAuth
+{
+ ///
+ /// OAuth provider info with a .
+ ///
+ public sealed class ServerUrlOAuthProviderInfo : BasicOAuthProviderInfo
+ {
+ ///
+ /// The remote service URL.
+ ///
+ public Uri ServerUrl { get; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The to build from.
+ public ServerUrlOAuthProviderInfo(OAuthProviderInfo providerInfo)
+ : base(providerInfo)
+ {
+ ServerUrl = providerInfo!.ServerUrl ?? throw new InvalidOperationException("ServerUrl not set!");
+ }
+ }
+}
diff --git a/src/Tgstation.Server.Host/GraphQL/Types/User.cs b/src/Tgstation.Server.Host/GraphQL/Types/User.cs
index 7e993fd358..721fbe9eef 100644
--- a/src/Tgstation.Server.Host/GraphQL/Types/User.cs
+++ b/src/Tgstation.Server.Host/GraphQL/Types/User.cs
@@ -7,6 +7,7 @@ using HotChocolate.Types.Relay;
using Tgstation.Server.Host.Authority;
using Tgstation.Server.Host.GraphQL.Interfaces;
+using Tgstation.Server.Host.GraphQL.Types.OAuth;
using Tgstation.Server.Host.Models.Transformers;
using Tgstation.Server.Host.Security;