This is a React Single Page Application (SPA) that retrieves a JWT token from Azure AD using MSAL and then consumes a .NET API.
It must be single-tenant. This identity is used to manage user access.
- Navigate to the Azure portal and select the
Microsoft Entra ID
. - Select
Manage > App Registrations
blade on the left, then selectNew registration
. - In the Register an application page that appears, under
Supported account types
, selectAccounts in this organizational directory only
and click onRegister
. - In the
Overview
blade, find and note theApplication (client) ID
. You use this value in your app's configuration file(s) later in your code.
First install az cli and sign in az login --allow-no-subscriptions
, then run:
echo "Name of Client Identity? (Type and press enter to continue)" && read -r CLIENT_NAME
CLIENT_ID=$(az ad app create --display-name $CLIENT_NAME --sign-in-audience AzureADMyOrg --query appId --output tsv)
It must be single-tenant. This identity is used to manage user access.
- In the Overview blade, find and note the
Application (client) ID
. You use this value in your app's configuration file(s) later in your code. - In the app's registration screen, select the Authentication blade to the left.
- If you don't have a platform added, select Add a platform and select the Single-page application option.
- In the Redirect URI section enter the following redirect URIs:
1.
http://localhost:3002
1.http://localhost:3002/redirect.html
- Click Save to save your changes.
cat <<EOF > redirectUris.json
{
"redirectUris": [
"http://localhost:3002",
"http://localhost:3002/redirect.html"
]
}
EOF
az ad app update --id $CLIENT_ID --set [email protected]
Since this app signs-in users, we will now proceed to select delegated permissions, which is is required by apps signing-in users.
- Select
Manage > API permissions
blade in the left to open the page where we add access to the APIs that your application needs: - Select the
Add a permission
button and then: - Select the Add a permission button and then:
- At this stage, the permissions are assigned correctly, the users themselves cannot consent to these permissions. To get around this problem, we'd let the tenant administrator consent on behalf of all users in the tenant. Select the
Grant 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 accounts in the tenant. You need to be a tenant admin to be able to carry out this operation.
NB: e1fe6dd8-ba31-4d61-89e7-88639da4683d
resource ID is Microsoft Graph > User.read
permission.
APP_ID=$(az ad app list --filter "displayname eq 'DNE Tools Sample API'" --query [0].appId | sed 's,",,g')
ressource_readwrite_id=$(az ad app show --id $APP_ID --query api.oauth2PermissionScopes[0].id | sed 's,",,g')
ressource_read_id=$(az ad app show --id $APP_ID --query api.oauth2PermissionScopes[1].id | sed 's,",,g')
cat <<EOF > requiredResourceAccess.json
[{
"resourceAppId": "$APP_ID",
"resourceAccess": [
{
"id": "$ressource_readwrite_id",
"type": "Scope"
},
{
"id": "$ressource_read_id",
"type": "Scope"
}
]
},
{
"resourceAppId": "00000003-0000-0000-c000-000000000000",
"resourceAccess": [
{
"id": "e1fe6dd8-ba31-4d61-89e7-88639da4683d",
"type": "Scope"
}
]
}]
EOF
az ad app update --id $CLIENT_ID --required-resource-accesses @requiredResourceAccess.json
To install project dependencies, run the following command:
npm install
Run the following command after the first build of the API to generate the API schema:
npm run api:generate:dev
Duplicate the .env.example
file and rename it to .env
. Then, modify the values as follows:
# Client ID of the SPA Application in Azure
VITE_AZURE_CLIENT_ID=aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaa
# Azure authority for the login (generally https://login.microsoftonline.com/{your_tenant_id})
VITE_AZURE_AUTHORITY=https://login.microsoftonline.com/bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbb
npm run dev
vite (documentation)
Vite is a modern frontend tooling solution used for serving the client in development and building/packaging the app for production. It is considered a modern alternative to webpack. The configuration file is located at vite.config.ts.
@azure/msal-browser & @azure/msal-react (documentation)
These libraries facilitate user redirection to the authentication page and retrieval of the JWT token. The MSAL instance is set up in src/main.tsx as follows:
export const msalInstance = new PublicClientApplication(MSAL_CONFIG)
The configuration for MSAL is found in src/config/auth-config.ts
Documentation for MSAL specific to React
@tanstack/react-query (documentation)
A simple state management library used to manage API services. It supports auto-caching, optimistic results, and request cancellation. Queries and mutations are managed within thesrc/features
folder.
@tanstack/react-router (documentation)
A fully type-safe React router with built-in data fetching, stale-while-revalidate caching, and first-class search-param APIs. Routes are defined by the folder structure of the components inside src/routes
, with route path types generated automatically by the @tanstack/router-vite-plugin
into src/routeTree.gen.ts
.
For example, src/routes/todo/$id.tsx maps to the route /todo/{id_of_the_todo}
and loads the corresponding view component.
eslint (documentation)
A static code analysis tool that helps enforce coding standards for the frontend. The configuration file is located in .eslintrc.cjs.
antd (documentation)
A comprehensive suite of React UI components that enhance UI development efficiency, similar to Bootstrap.
openapi-fetch / openapi-typescript (documentation)
Type-safe fetch client that generates TypeScript types from static OpenAPI schemas using Node.js. It ensures type safety when consuming the .NET API. The openapi.json file is created during the build phase of WebAppStarter.Api
and is located at /src/Api/bin/Debug/net8.0/openapi.json
. The npm run api:generate:dev
command then generates src/api/todo-schema.d.ts
from this file.
react-hook-form (documentation)
Provides efficient and flexible form management in React, supporting form validation, nested forms, array forms, and more.
zod (documentation)
Zod is a TypeScript library for schema validation with static type inference, primarily used withreact-hook-form
for validating form schemas. It can also be used for general JSON schema validation.
For example, the configuration file src/config/config.ts validates the CONFIG
variable, which is derived from the environment variables using a Zod schema.
// Create the validation schema
const configSchema = z.object({
azure: z.object({
authority: z.string(),
clientId: z.string(),
}),
todoApi: z.object({
endpoint: z.string(),
scopes: z.object({
read: z.array(z.string()),
write: z.array(z.string()),
}),
}),
})
// Infer the typescript type of the config from the schema
export type Config = z.infer<typeof configSchema>
// Create and parse the config schema (this will throw an error is the schema is not respected )
export const CONFIG: Config = configSchema.parse({
azure: {
authority: import.meta.env.VITE_AZURE_AUTHORITY,
clientId: import.meta.env.VITE_AZURE_CLIENT_ID,
},
todoApi: {
endpoint: import.meta.env.VITE_TODO_API_ENDPOINT_URL,
scopes: {
read: JSON.parse(import.meta.env.VITE_TODO_API_SCOPES_READ),
write: JSON.parse(import.meta.env.VITE_TODO_API_SCOPES_WRITE),
},
},
})
This documentation outlines the organizational structure of the React application's source code, detailing the purpose and functionality of each directory and key files within the project.
This directory manages all interactions with the API, including data fetching and mutations.
-
src/api/http-client.ts: Provides a
getHttpClient
function that creates a client for consuming the API with type safety, leveraging the generated types fromsrc/api/todo-schema.d.ts
. It includes middlewares to append the user's JWT token to every request. -
src/api/todo-schema.d.ts
: Contains the generated type definitions for theWebAppStarter.Api
, created by thenpm run generated-api
command. -
src/api/query-client.ts: An instance of
@tanstack/react-query
used for handling queries and mutations throughout the application. -
src/api/todo.ts: Defines CRUD functions (
DELETE
,GET
,POST
,PUT
) for interacting with the todo API, utilizing the http client.
This folder houses reusable components that are used either within route components or elsewhere in the application.
This directory contains configuration files for the application.
-
src/config/config.ts: Stores the global configuration of the application, assembling the
CONFIG
object from environment variables defined in.env
. -
src/config/auth-config.ts: Contains the authentication settings for MSAL.
Includes all the @tanstack/react-query
queries and mutations, which are utilized by React components to fetch or update data from the API.
Contains route guards used by routes in order to restrict the access of a route.
- src/guards/authenticate-guard.ts: Verifies user authentication and redirects unauthenticated users to the login page if necessary.
Manages all application routes, structured and handled via @tanstack/router. For naming conventions and routing structures, refer to the File-Based Routing Guide.
Contains utility functions and classes that support various functionalities across the application.
-
src/utils/claim-utils.ts: A helper utility for constructing a claims table from a ID Token Claims, demonstrating how to extract claim information for a user.
-
src/utils/msal-navigation-client.ts: A custom NavigationClient class to bind
@tanstack/react-router
to the instance of MSAL this allows MSAL to redirect to the user coming page when doing a login.
This structure ensures a modular and clear organization of code, simplifying maintenance and scalability of the application.