Skip to content

ASP.NET application with Multitenant authentication, SSO, Application only permissions.

Notifications You must be signed in to change notification settings

ivanenkomaksym/asp-net-azure-sample

Repository files navigation

asp-net-azure-sample

This sample demonstrates how to configure ASP.NET application for:

Dependencies

.NET8

Authentication

Azure

  1. Sign in to the Azure portal using either a work or school account or a personal Microsoft account
  2. Register the service web application
    • In the Supported account types section, select Accounts in any organizational directory
    • In the Expose an API make sure Application ID URI contains "api://[client id]"
    • in the Expose an API add scope "api://[client id]/[Application name]"
    • In the App roles add new access_as_application role for Applications as Allowed member types
    • In the API permissions add Azure Service Management and select user_impersonation
  3. Register swagger client application
    • Add https://localhost:44321 to Authentication/Redirect URIs
    • In the Authentication/Implicit grant and hybrid flows section, check ID tokens
    • In the Certificates & secrets generate new client secret and save the value
    • In the API permissions add My APIs, select service application from step 2 and choose Delegated permissions
  4. Register UI client application
    • In the Supported account types section, select Accounts in any organizational directory
    • in the Redirect URIs select Single-page application (SPA) and add https://localhost:44321
    • In the API permissions add My APIs, select service application from step 2 and choose Delegated permissions
    • Get back to service web application Azure configuration from step 2 and add this UI client application id to Expose an API/Authorized client applications
  5. Register daemon client application
    • In the Certificates & secrets generate new client secret and save the value
    • In the API permissions add My APIs, select service application from step 2, choose Application permissions and access_as_application.
    • At this stage permissions are assigned correctly but the client app does not allow interaction. Therefore no consent can be presented via a UI and accepted to use the service app. Click the Grant/revoke admin consent for {tenant} button, and then select Yes when you are asked if you want to grant consent for the requested permissions for all account in the tenant. You need to be an Azure AD tenant admin to do this.
  6. Fill in appsettings.json
  7. Fill in react-spa\src\authConfig.js
  8. Start server application by running dotnet run in AspNetAzureSample.WebApi (running on http://localhost:5000 by default).
  9. Start client application by running npm start in react-spa (running on http://localhost:3000 by default).

Google Cloud Provider

  1. Sign in to the Google Console
  2. In APIs & Services/Credentials create new credentials
  3. In the appsettings.json set Google:Enable to true and fill in Google:ClientId.
  4. Configure necessary Javascript origins and redirect URIs, including https://developers.google.com/oauthplayground
  5. Go to OAuth2 Playground
  6. Press top right settings (gear) icon (OAuth 2.0 configuration)
  7. Tick Use your own OAuth credentials and enter OAuth Client ID and OAuth Client secret
  8. At the bottom enter scopes:
openid https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile
  1. Press Authorize APIs.
  2. On the next screen choose the account (optional screen) and give the permissions to the app.
  3. Press Exchange authorization code for tokens
  4. Get your non-expiring refresh_token and put it into appsettings.json
  5. To get an id_token using refresh_token:
curl -d "client_id=YOUR_APP_CLIENT_ID&client_secret=YOUR_APP_CLIENT_SECRET&grant_type=refresh_token&refresh_token=YOUR_APP_REFRESH_TOKEN" "https://oauth2.googleapis.com/token"

How to use this sample

Swagger UI

  1. Open http://localhost:5000/swagger/index.html
  2. Click Authorize using accounts from different tenants.

Access from daemon client application without real user

  1. In Postman get an access token as described in Get an access token
  2. Using generated token access https://localhost:5000/Maintenance

React Single Page Application

  1. Open http://localhost:3000/
  2. Click Login and choose one of the supported options:
    • Sign in with Google Access Token
    • Google one tap
    • Microsoft

Alt text

  1. Click Get Weather button. It will send the request to server with corresponding bearer token.

Alt text

  1. Click Profile to see your profile's information retrieved from the corresponding identity provider.

Alt text

Authentication for Testing

In certain scenarios, it may be necessary to run the application with authentication enabled but without using a real user, especially during testing. This sample includes a special middleware that ensures the return of an authenticated user without actual authentication. This middleware is only added when the ASPNETCORE_ENVIRONMENT is set to Testing.

You can initiate the testing profile from Visual Studio or by running the following command:

dotnet run --environment Testing

When running in this mode, attempting to access the API without proper authentication in Swagger or a client will be restricted. However, you can still access the API by including the header X-Testing-Name=<username> in the request, for instance, when using Postman at https://localhost:44321/WeatherForecast.

Cookie-based authentication

  1. Open Swagger UI via http://localhost:5000/swagger/index.html
  2. Click Authorize button and authenticate with your Microsoft credentials
  3. Confirm you can execute http://localhost:5000/WeatherForecast. In this case Bearer authentication scheme is challenged.
dbug: Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler[8]
      AuthenticationScheme: Bearer was successfully authenticated.
info: AspNetAzureSample.UserProviders.DefaultUserProvider[0]
      DefaultUserProvider: received '' user name.
  1. Click Authorize button again and click Logout
  2. Confirm you cannot anymore execute http://localhost:5000/WeatherForecast and get 401 Error: Unauthorized
  3. Execute /register with body:
{
  "email": "alice@gmail.com",
  "password": "string1!"
}

You can also use hardcoded users:

admin@example.com   P@ssword1
alice@example.com   P@ssword1
bob@example.com     P@ssword1
  1. Execute /login with the same body. Set useCookies to true. New cookie will appear in the browser, a sample cookie record is shown: Alt text
  2. Confirm you can again execute http://localhost:5000/WeatherForecast. In this case Identity.BearerAndApplication authentication scheme is challenged.
dbug: Microsoft.Extensions.DependencyInjection.IdentityServiceCollectionExtensions+CompositeIdentityHandler[8]
      AuthenticationScheme: Identity.BearerAndApplication was successfully authenticated.
info: AspNetAzureSample.UserProviders.DefaultUserProvider[0]
      DefaultUserProvider: received 'alice@gmail.com' user name.

If you remove the cookie, authentication will again fail.

Storage support

You can switch between storage types by Storage:StorageType property in the appsettings.json:

  • InMemory
  • MySql
  • SqlServer

To run MySql docker image:

docker run -d --name mysql-container -e MYSQL_ROOT_PASSWORD=my-secret-pw -e MYSQL_DATABASE=TweetsDb -e MYSQL_USER=myuser -e MYSQL_PASSWORD=mypassword -p 3306:3306 mysql:latest

If you want to switch between different databases:

dotnet ef migrations remove
dotnet ef migrations add InitialCreate
dotnet ef database update

3 dummy users are seeded to easily test solution:

admin@example.com   P@ssword1
alice@example.com   P@ssword1
bob@example.com     P@ssword1

References

About

ASP.NET application with Multitenant authentication, SSO, Application only permissions.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published