Linked Roles
DisCatSharp.Hosting.AspNetCore includes a small helper layer for Discord linked roles.
Those helpers live under DisCatSharp.Hosting.AspNetCore.LinkedRoles.
The package does not own your app-specific verification page or your account-linking business logic. Instead, it helps with the parts that are repetitive across apps:
- computing the public verification URL
- syncing linked-role metadata records with Discord
- publishing a user's role connection from a successful OAuth callback result
Feature boundary
The linked-roles verification URL is your public app route. It is not one of the ingress endpoints created by MapDisCatSharpIngress().
That split is intentional:
- ingress endpoints handle Discord-owned HTTP surfaces such as OAuth callbacks and interactions
- linked roles help you keep your own verification route and Discord's application metadata in sync
Register the helper
using DisCatSharp.Hosting.AspNetCore;
builder.Services
.AddDisCatSharpAspNetCore(configureOAuth: options =>
{
options.ClientId = 123456789012345678;
options.ClientSecret = "YOUR_CLIENT_SECRET";
options.RedirectUri = "https://bot.example.com/discord/oauth/callback";
})
.AddDiscordLinkedRolesSupport(options =>
{
options.VerificationPath = "role-connections/verify";
});
Compute the verification URL
Discord's Linked Roles Verification URL is your app's public entry point for the linked-role flow.
using DisCatSharp.Hosting.AspNetCore.LinkedRoles;
var linkedRoles = app.Services.GetRequiredService<DiscordLinkedRolesService>();
var verificationUrl = linkedRoles.GetVerificationUrl(new Uri("https://bot.example.com"));
With the default ingress settings and VerificationPath = "role-connections/verify", the computed URL becomes:
https://bot.example.com/role-connections/verify
Use that value in the Developer Portal's Linked Roles Verification URL field.
If you want DisCatSharp to update the application setting for you:
await linkedRoles.UpdateVerificationUrlAsync(discordClient, new Uri("https://bot.example.com"));
Because the verification URL belongs to your app, you still need to expose that route yourself:
app.MapGet("/role-connections/verify", () => Results.Text("Render your verification experience here."));
Sync metadata records
Register a metadata provider:
using DisCatSharp.Entities;
using DisCatSharp.Enums;
using DisCatSharp.Hosting.AspNetCore;
using DisCatSharp.Hosting.AspNetCore.LinkedRoles;
builder.Services.AddDiscordLinkedRolesMetadataProvider<MyLinkedRolesMetadataProvider>();
public sealed class MyLinkedRolesMetadataProvider : IDiscordLinkedRolesMetadataProvider
{
public ValueTask<IReadOnlyList<DiscordApplicationRoleConnectionMetadata>> GetMetadataAsync(CancellationToken cancellationToken = default)
=> new((IReadOnlyList<DiscordApplicationRoleConnectionMetadata>)
[
new DiscordApplicationRoleConnectionMetadata(
ApplicationRoleConnectionMetadataType.BooleanEqual,
"verified",
"Verified Account",
"Whether the account is verified")
]);
}
Then synchronize the schema:
await linkedRoles.SynchronizeMetadataAsync(discordClient);
The helper compares the current metadata with the provider output and only sends an update when the schema differs.
Publish a user's role connection from OAuth
After your OAuth callback succeeds, use the exchanged access token captured by DiscordOAuthCallbackResult:
var callbackResult = await oauthCallbackHandler.HandleAsync(callbackRequest);
await linkedRoles.PublishRoleConnectionAsync(
oauth2Client,
callbackResult,
platformName: "Example",
platformUsername: "lala",
metadata: new ApplicationRoleConnectionMetadata()
.AddMetadata("verified", "1"));
The callback result must be successful and the granted scope must include role_connections.write.
You can check that requirement ahead of time with linkedRoles.HasRoleConnectionsWriteScope(callbackResult).
Existing app vs self-host
The helper service is hosting-model agnostic.
- existing ASP.NET Core app: register the helper, map your verification route, and optionally use the OAuth callback endpoint
- self-host mode: register the same helper services, but your linked-roles verification page still belongs to your own app surface outside the self-hosted ingress routes
What you still own
The helper does not replace your application logic. You still need to provide:
- the verification page or route at the configured verification URL
- any user/account lookup required by your external service
- the metadata values you want to publish for each user
To validate the resulting verification URL against the Developer Portal, see Proxy and Validation Helpers.