This tutorial continues on the chat room application introduced in Create a chat room with SignalR Service. Complete that quickstart first to set up your chat room.
In this tutorial, learn how to create and integrate your authentication method using Microsoft Azure SignalR Service.
The authentication initially used in the quickstart's chat room application is too simple for real-world scenarios. The application allows each client to claim who they are, and the server simply accepts that. This approach is ineffective in the real-world because malicious users can use fake identities to access sensitive data.
GitHub provides authentication APIs based on a popular industry-standard protocol called OAuth. These APIs allow third-party applications to authenticate GitHub accounts. In this tutorial, you can use these APIs to implement authentication through a GitHub account before allowing client logins to the chat room application. After GitHub account authentication, the account information will be added as a cookie to be used by the web client to authenticate.
For more information on the OAuth authentication APIs provided through GitHub, see Basics of Authentication.
You can use any code editor to complete the steps in this quickstart. However, Visual Studio Code is an excellent option available on the Windows, macOS, and Linux platforms.
Open a web browser and navigate to https://github.com and sign into your account.
For your account, navigate to Settings > Developer settings > OAuth Apps, and select New OAuth App under OAuth Apps.
Use the following settings for the new OAuth App, then select Register application:
Setting Name
Suggested Value
Description
Application name
Azure SignalR Chat
The GitHub user should be able to recognize and trust the app they're authenticating with.
Homepage URL
https://localhost:5001
Application description
A chat room sample using the Azure SignalR Service with GitHub authentication
A useful description of the application that helps your application users understand the context of the authentication being used.
Authorization callback URL
https://localhost:5001/signin-github
This setting is the most important setting for your OAuth application. It's the callback URL that GitHub returns the user to after successful authentication. In this tutorial, you must use the default callback URL for the AspNet.Security.OAuth.GitHub package, /signin-github.
Once the new OAuth app registration is complete, add the Client ID and Client Secret to Secret Manager using the following commands. Replace Your_GitHub_Client_Id and Your_GitHub_Client_Secret with the values for your OAuth app.
.NET CLI
dotnetuser-secrets set GitHubClientId Your_GitHub_Client_Id
dotnetuser-secrets set GitHubClientSecret Your_GitHub_Client_Secret
Update Program.cs to support GitHub authentication
Add a reference to the latest AspNet.Security.OAuth.GitHub packages and restore all packages.
.NET CLI
dotnetadd package AspNet.Security.OAuth.GitHub
Open Program.cs, and update the code to the following code snippet:
C#
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OAuth;
using System.Net.Http.Headers;
using System.Security.Claims;
var builder = WebApplication.CreateBuilder(args);
builder.Services
.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie()
.AddGitHub(options =>
{
options.ClientId = builder.Configuration["GitHubClientId"] ?? "";
options.ClientSecret = builder.Configuration["GitHubClientSecret"] ?? "";
options.Scope.Add("user:email");
options.Events = new OAuthEvents
{
OnCreatingTicket = GetUserCompanyInfoAsync
};
});
builder.Services.AddControllers();
builder.Services.AddSignalR().AddAzureSignalR();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapControllers();
app.MapHub<ChatSampleHub>("/chat");
app.Run();
staticasync Task GetUserCompanyInfoAsync(OAuthCreatingTicketContext context)
{
var request = new HttpRequestMessage(HttpMethod.Get, context.Options.UserInformationEndpoint);
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", context.AccessToken);
var response = await context.Backchannel.SendAsync(request,
HttpCompletionOption.ResponseHeadersRead, context.HttpContext.RequestAborted);
var user = await response.Content.ReadFromJsonAsync<GitHubUser>();
if (user?.company != null)
{
context.Principal?.AddIdentity(new ClaimsIdentity(new[]
{
new Claim("Company", user.company)
}));
}
}
classGitHubUser
{
publicstring? company { get; set; }
}
Inside the code, AddAuthentication and UseAuthentication are used to add authentication support with the GitHub OAuth app, and GetUserCompanyInfoAsync helper method is sample code showing how to load the company info from GitHub OAuth and save into user identity. You might also notice that UseHttpsRedirection() is used since GitHub OAuth set secure cookie that only passes through to secured https scheme. Also don't forget to update the local Properties/launchSettings.json to add https endpoint:
In this section, you implement a Login API that authenticates clients using the GitHub OAuth app. Once authenticated, the API adds a cookie to the web client response before redirecting the client back to the chat app. That cookie is then used to identify the client.
Add a new controller code file to the GitHubChat\Controllers directory. Name the file AuthController.cs.
Add the following code for the authentication controller. Make sure to update the namespace, if your project directory wasn't GitHubChat:
C#
using AspNet.Security.OAuth.GitHub;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Mvc;
namespaceGitHubChat.Controllers
{
[Route("/")]
publicclassAuthController : Controller
{
[HttpGet("login")]
public IActionResult Login()
{
if (User.Identity == null || !User.Identity.IsAuthenticated)
{
return Challenge(GitHubAuthenticationDefaults.AuthenticationScheme);
}
HttpContext.Response.Cookies.Append("githubchat_username", User.Identity.Name ?? "");
HttpContext.SignInAsync(User);
return Redirect("/");
}
}
}
Save your changes.
Update the Hub class
By default, web client connects to SignalR Service using an access token generated by the Azure SignalR SDK automatically.
In this section, you integrate the real authentication workflow by adding the Authorize attribute to the hub class, and update the hub methods to read the username from the authenticated user's claim.
Open Hub\ChatSampleHub.cs and update the code to the below code snippet. The code adds the Authorize attribute to the ChatSampleHub class, and uses the user's authenticated identity in the hub methods. Also, the OnConnectedAsync method is added, which logs a system message to the chat room each time a new client connects.
C#
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.SignalR;
[Authorize]
publicclassChatSampleHub : Hub
{
publicoverride Task OnConnectedAsync()
{
return Clients.All.SendAsync("broadcastMessage", "_SYSTEM_", $"{Context.User?.Identity?.Name} JOINED");
}
// Uncomment this line to only allow user in Microsoft to send message//[Authorize(Policy = "Microsoft_Only")]public Task BroadcastMessage(string message)
{
return Clients.All.SendAsync("broadcastMessage", Context.User?.Identity?.Name, message);
}
public Task Echo(string message)
{
var echoMessage = $"{message} (echo from server)";
return Clients.Client(Context.ConnectionId).SendAsync("echo", Context.User?.Identity?.Name, echoMessage);
}
}
Save your changes.
Update the web client code
Open wwwroot\index.html and replace the code that prompts for the username with code to use the cookie returned by the authentication controller.
Update the code inside function getUserName in index.html to the following to use cookies:
JavaScript
functiongetUserName() {
// Get the user name cookie.functiongetCookie(key) {
var cookies = document.cookie.split(";").map((c) => c.trim());
for (var i = 0; i < cookies.length; i++) {
if (cookies[i].startsWith(key + "="))
returnunescape(cookies[i].slice(key.length + 1));
}
return"";
}
return getCookie("githubchat_username");
}
Update onConnected function to remove the username parameter when invoking hub method broadcastMessage and echo:
JavaScript
functiononConnected(connection) {
console.log("connection started");
connection.send("broadcastMessage", "_SYSTEM_", username + " JOINED");
document.getElementById("sendmessage").addEventListener("click", function (event) {
// Call the broadcastMessage method on the hub.if (messageInput.value) {
connection.invoke("broadcastMessage", messageInput.value)
.catch((e) => appendMessage("_BROADCAST_", e.message));
}
// Clear text box and reset focus for next comment.
messageInput.value = "";
messageInput.focus();
event.preventDefault();
});
document.getElementById("message").addEventListener("keypress", function (event) {
if (event.keyCode === 13) {
event.preventDefault();
document.getElementById("sendmessage").click();
returnfalse;
}
});
document.getElementById("echo").addEventListener("click", function (event) {
// Call the echo method on the hub.
connection.send("echo", messageInput.value);
// Clear text box and reset focus for next comment.
messageInput.value = "";
messageInput.focus();
event.preventDefault();
});
}
At the bottom of index.html, update the error handler for connection.start() as shown below to prompt the user to sign in.
JavaScript
connection.start()
.then(function () {
onConnected(connection);
})
.catch(function (error) {
console.error(error.message);
if (error.statusCode && error.statusCode === 401) {
appendMessage(
"_BROADCAST_",
"You\"re not logged in. Click <a href="/login">here</a> to login with GitHub."
);
}
});
Save your changes.
Build and Run the app locally
Save changes to all files.
Execute the following command to run the web app locally:
.NET CLI
dotnetrun
The app is hosted locally on port 5000 by default:
Output
info: Microsoft.Hosting.Lifetime[14]
Now listening on: http://0.0.0.0:5000
info: Microsoft.Hosting.Lifetime[14]
Now listening on: https://0.0.0.0:5001
info: Microsoft.Hosting.Lifetime[0]
Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
Hosting environment: Development
Launch a browser window and navigate to https://localhost:5001. Select the here link at the top to sign in with GitHub.
You're prompted to authorize the chat app's access to your GitHub account. Select the Authorize button.
You're redirected back to the chat application and logged in with your GitHub account name. The web application determined your account name by authenticating you using the new authentication you added.
With the chat app now performs authentication with GitHub and stores the authentication information as cookies, the next step involves deploying it to Azure.
This approach enables other users to authenticate using their respective accounts and communicate from various workstations.
If you prefer to run CLI reference commands locally, install the Azure CLI. If you're running on Windows or macOS, consider running Azure CLI in a Docker container. For more information, see How to run the Azure CLI in a Docker container.
If you're using a local installation, sign in to the Azure CLI by using the az login command. To finish the authentication process, follow the steps displayed in your terminal. For other sign-in options, see Sign in with the Azure CLI.
When you're prompted, install the Azure CLI extension on first use. For more information about extensions, see Use extensions with the Azure CLI.
Run az version to find the version and dependent libraries that are installed. To upgrade to the latest version, run az upgrade.
In this section, you use the Azure CLI to create a new web app in Azure App Service to host your ASP.NET application in Azure. The web app is configured to use local Git deployment. The web app is also configured with your SignalR connection string, GitHub OAuth app secrets, and a deployment user.
When creating the following resources, make sure to use the same resource group that your SignalR Service resource resides in. This approach makes cleanup a lot easier later when you want to remove all the resources. The examples given assume you used the group name recommended in previous tutorials, SignalRTestResources.
Create the web app and plan
Copy the text for the commands below and update the parameters. Paste the updated script into the Azure Cloud Shell, and press Enter to create a new App Service plan and web app.
Azure CLI
#========================================================================#=== Update these variable for your resource group name. ===#========================================================================
ResourceGroupName=SignalRTestResources
#========================================================================#=== Update these variable for your web app. ===#========================================================================
WebAppName=myWebAppName
WebAppPlan=myAppServicePlanName
# Create an App Service plan.az appservice plan create --name$WebAppPlan--resource-group$ResourceGroupName \
--sku FREE
# Create the new Web Appaz webapp create --name$WebAppName--resource-group$ResourceGroupName \
--plan$WebAppPlan
Parameter
Description
ResourceGroupName
This resource group name was suggested in previous tutorials. It's a good idea to keep all tutorial resources grouped together. Use the same resource group you used in the previous tutorials.
WebAppPlan
Enter a new, unique, App Service Plan name.
WebAppName
This parameter is the name of the new web app and part of the URL. Make it unique. For example, signalrtestwebapp22665120.
Add app settings to the web app
In this section, you add app settings for the following components:
SignalR Service resource connection string
GitHub OAuth app client ID
GitHub OAuth app client secret
Copy the text for the commands below and update the parameters. Paste the updated script into the Azure Cloud Shell, and press Enter to add the app settings:
Azure CLI
#========================================================================#=== Update these variables for your GitHub OAuth App. ===#========================================================================
GitHubClientId=1234567890
GitHubClientSecret=1234567890#========================================================================#=== Update these variables for your resources. ===#========================================================================
ResourceGroupName=SignalRTestResources
SignalRServiceResource=mySignalRresourcename
WebAppName=myWebAppName
# Get the SignalR primary connection string
primaryConnectionString=$(az signalr key list --name$SignalRServiceResource \
--resource-group$ResourceGroupName--query primaryConnectionString -o tsv)
#Add an app setting to the web app for the SignalR connectionaz webapp config appsettings set --name$WebAppName \
--resource-group$ResourceGroupName \
--settings"Azure__SignalR__ConnectionString=$primaryConnectionString"#Add the app settings to use with GitHub authenticationaz webapp config appsettings set --name$WebAppName \
--resource-group$ResourceGroupName \
--settings"GitHubClientId=$GitHubClientId"az webapp config appsettings set --name$WebAppName \
--resource-group$ResourceGroupName \
--settings"GitHubClientSecret=$GitHubClientSecret"
Parameter
Description
GitHubClientId
Assign this variable the secret Client ID for your GitHub OAuth App.
GitHubClientSecret
Assign this variable the secret password for your GitHub OAuth App.
ResourceGroupName
Update this variable to be the same resource group name you used in the previous section.
SignalRServiceResource
Update this variable with the name of the SignalR Service resource you created in the quickstart. For example, signalrtestsvc48778624.
WebAppName
Update this variable with the name of the new web app you created in the previous section.
Configure the web app for local Git deployment
In the Azure Cloud Shell, paste the following script. This script creates a new deployment user name and password that you use when deploying your code to the web app with Git. The script also configures the web app for deployment with a local Git repository, and returns the Git deployment URL.
Azure CLI
#========================================================================#=== Update these variables for your resources. ===#========================================================================
ResourceGroupName=SignalRTestResources
WebAppName=myWebAppName
#========================================================================#=== Update these variables for your deployment user. ===#========================================================================
DeploymentUserName=myUserName
DeploymentUserPassword=myPassword
# Add the desired deployment user name and passwordaz webapp deployment user set --user-name$DeploymentUserName \
--password$DeploymentUserPassword# Configure Git deployment and note the deployment URL in the outputaz webapp deployment source config-local-git --name$WebAppName \
--resource-group$ResourceGroupName \
--query[url]-o tsv
Parameter
Description
DeploymentUserName
Choose a new deployment user name.
DeploymentUserPassword
Choose a password for the new deployment user.
ResourceGroupName
Use the same resource group name you used in the previous section.
WebAppName
This parameter is the name of the new web app you created previously.
Make a note the Git deployment URL returned from this command. You use this URL later.
Deploy your code to the Azure web app
To deploy your code, execute the following commands in a Git shell.
Navigate to the root of your project directory. If you don't have the project initialized with a Git repository, execute following command:
Bash
git init
Add a remote for the Git deployment URL you noted earlier:
Bash
git remote add Azure <your git deployment url>
Stage all files in the initialized repository and add a commit.
Bash
git add -A
git commit -m "init commit"
Deploy your code to the web app in Azure.
Bash
git push Azure main
You're prompted to authenticate in order to deploy the code to Azure. Enter the user name and password of the deployment user you created above.
Update the GitHub OAuth app
The last thing you need to do is update the Homepage URL and Authorization callback URL of the GitHub OAuth app to point to the new hosted app.
Open https://github.com in a browser and navigate to your account's Settings > Developer settings > Oauth Apps.
Select on your authentication app and update the Homepage URL and Authorization callback URL as shown below:
Navigate to your web app URL and test the application.
Clean up resources
If you'll be continuing to the next tutorial, you can keep the resources created in this quickstart and reuse them with the next tutorial.
Otherwise, if you're finished with the quickstart sample application, you can delete the Azure resources created in this quickstart to avoid charges.
Important
Deleting a resource group is irreversible and that the resource group and all the resources in it are permanently deleted. Make sure that you do not accidentally delete the wrong resource group or resources. If you created the resources for hosting this sample inside an existing resource group that contains resources you want to keep, you can delete each resource individually from their respective blades instead of deleting the resource group.
Sign in to the Azure portal and select Resource groups.
In the Filter by name... textbox, type the name of your resource group. The instructions for this article used a resource group named SignalRTestResources. On your resource group in the result list, click ... then Delete resource group.
You're asked to confirm the deletion of the resource group. Type the name of your resource group to confirm, and select Delete.
After a few moments, the resource group and all of its contained resources are deleted.
Next steps
In this tutorial, you added authentication with OAuth to provide a better approach to authentication with Azure SignalR Service. To learn more about using Azure SignalR Server, continue to the Azure CLI samples for SignalR Service.
Change a JavaScript web app update mechanism from polling to real-time push-based architecture with SignalR Service, Azure Cosmos DB and Azure Functions. Use Vue.js and JavaScript to use SignalR using Visual Studio Code.
Build end-to-end solutions in Microsoft Azure to create Azure Functions, implement and manage web apps, develop solutions utilizing Azure storage, and more.