Skip to content

Commit e2c847d

Browse files
authored
Merge pull request #111 from 4gust/main
Updating the sample application for updating profile through MFA
2 parents cfa4a13 + 1f88b0b commit e2c847d

File tree

10 files changed

+1657
-284
lines changed

10 files changed

+1657
-284
lines changed
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License.
4+
*/
5+
6+
require("dotenv").config({ path: ".env.dev" });
7+
8+
const TENANT_SUBDOMAIN =
9+
process.env.TENANT_SUBDOMAIN || "Enter_the_Tenant_Subdomain_Here";
10+
const TENANT_ID = process.env.TENANT_ID || "Enter_the_Tenant_ID_Here";
11+
const REDIRECT_URI =
12+
process.env.REDIRECT_URI || "http://localhost:3000/auth/redirect";
13+
const POST_LOGOUT_REDIRECT_URI =
14+
process.env.POST_LOGOUT_REDIRECT_URI || "http://localhost:3000";
15+
16+
/**
17+
* Configuration object to be passed to MSAL instance on creation.
18+
* For a full list of MSAL Node configuration parameters, visit:
19+
* https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-node/docs/configuration.md
20+
*/
21+
const msalConfig = {
22+
auth: {
23+
clientId:
24+
process.env.CLIENT_ID ||
25+
"Enter_the_Edit_Profile_Service_Application_Id_Here", // 'Application (client) ID' of the Edit_Profile Service App registration in Microsoft Entra admin center - this value is a GUID
26+
authority:
27+
process.env.AUTHORITY || `https://${TENANT_SUBDOMAIN}.ciamlogin.com/`, // Replace the placeholder with your external tenant name
28+
clientSecret: process.env.CLIENT_SECRET || "Enter_the_Client_Secret_Here", // Client secret generated from the app registration in Microsoft Entra admin center
29+
},
30+
system: {
31+
loggerOptions: {
32+
loggerCallback(loglevel, message, containsPii) {
33+
console.log(message);
34+
},
35+
piiLoggingEnabled: false,
36+
logLevel: "Info",
37+
},
38+
},
39+
};
40+
41+
const GRAPH_API_ENDPOINT = process.env.GRAPH_API_ENDPOINT || "graph_end_point";
42+
// Refers to the user that is single user singed in.
43+
// https://learn.microsoft.com/en-us/graph/api/user-update?view=graph-rest-1.0&tabs=http
44+
const GRAPH_ME_ENDPOINT = GRAPH_API_ENDPOINT + "v1.0/me";
45+
46+
module.exports = {
47+
msalConfig,
48+
REDIRECT_URI,
49+
POST_LOGOUT_REDIRECT_URI,
50+
TENANT_SUBDOMAIN,
51+
GRAPH_API_ENDPOINT,
52+
GRAPH_ME_ENDPOINT,
53+
TENANT_ID,
54+
};
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
var axios = require("axios");
2+
3+
/**
4+
* Makes an Authorization "Bearer" request with the given accessToken to the given endpoint.
5+
* @param endpoint
6+
* @param accessToken
7+
* @param method
8+
*/
9+
const fetch = async (endpoint, accessToken, method = "GET", data = null) => {
10+
const options = {
11+
headers: {
12+
Authorization: `Bearer ${accessToken}`,
13+
},
14+
};
15+
console.log(`request made to ${endpoint} at: ` + new Date().toString());
16+
17+
switch (method) {
18+
case "GET":
19+
const response = await axios.get(endpoint, options);
20+
return await response.data;
21+
case "POST":
22+
return await axios.post(endpoint, data, options);
23+
case "DELETE":
24+
return await axios.delete(endpoint + `/${data}`, options);
25+
case "PATCH":
26+
return await axios.patch(endpoint, (ReqBody = data), options);
27+
default:
28+
return null;
29+
}
30+
};
31+
32+
module.exports = { fetch };
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// Import necessary modules
2+
const express = require("express");
3+
const msal = require("@azure/msal-node");
4+
const app = express();
5+
const port = 3001;
6+
const { v4: uuidv4 } = require("uuid");
7+
const {
8+
msalConfig,
9+
GRAPH_ME_ENDPOINT,
10+
TENANT_SUBDOMAIN,
11+
TENANT_ID,
12+
} = require("./authConfig");
13+
14+
var { fetch } = require("./fetch");
15+
16+
// Middleware to parse incoming JSON requests
17+
app.use(express.json());
18+
19+
const cca = new msal.ConfidentialClientApplication(msalConfig);
20+
21+
// Function to acquire token using client credentials
22+
async function getAccessToken(tokenRequest) {
23+
try {
24+
const response = await cca.acquireTokenOnBehalfOf(tokenRequest);
25+
return response.accessToken;
26+
} catch (error) {
27+
console.error("Error acquiring token:", error);
28+
throw error;
29+
}
30+
}
31+
32+
// Define the updateUserInfo endpoint
33+
app.post("/updateUserInfo", async (req, res) => {
34+
try {
35+
const tokenRequest = {
36+
oboAssertion: req.headers.authorization.replace("Bearer ", ""),
37+
authority: `https://${TENANT_SUBDOMAIN}.ciamlogin.com/${TENANT_ID}`,
38+
scopes: ["User.ReadWrite"],
39+
correlationId: `${uuidv4()}`,
40+
};
41+
42+
let accessToken = await getAccessToken(tokenRequest);
43+
fetch(GRAPH_ME_ENDPOINT, accessToken, "PATCH", req.body)
44+
.then((response) => {
45+
if (response.status === 204) {
46+
res.status(response.status);
47+
res.json({ message: "Success" });
48+
} else {
49+
res.status(502);
50+
res.json({ message: "Failed, " + response.body });
51+
}
52+
})
53+
.catch((error) => {
54+
res.status(502);
55+
res.json({ message: "Failed, " + error });
56+
});
57+
} catch (err) {
58+
res.json({ message: "Failed, " + err });
59+
}
60+
});
61+
62+
// Start the server
63+
app.listen(port, () => {
64+
console.log(`Server is running on http://localhost:${port}`);
65+
});

0 commit comments

Comments
 (0)