I am trying to authenticate users into my webapp using my company's ADFS 2016 server.
Using nodejs and express. I am able to authenticate properly but I do not receive any user profile information. I need at least email, name and surname.
Here is the relevant part of the code:
app.get("/login", (req: Request, res: Response) => {
const redirectUri = `http://localhost:${PORT}/redirect`; // Redirect URI after authentication
const queryParams = new URLSearchParams({
response_type: "code",
client_id: CLIENT_ID,
redirect_uri: redirectUri,
resource: "urn:microsoft:userinfo",
scope: "openid"
});
res.redirect(`${AUTHORITY}/oauth2/authorize?${queryParams}`);
});
app.get("/redirect", async (req: Request, res: Response) => {
const code = req.query.code;
const data = {
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET,
grant_type: "authorization_code",
code: code,
redirect_uri: `http://localhost:${PORT}/redirect`
};
try {
const response = await axios.post(TOKEN_ENDPOINT, data, {
headers: {
"Content-Type": "application/x-www-form-urlencoded"
}
});
const accessToken = response.data.access_token;
const userInfo = await axios.get(USERINFO_ENDPOINT, {
headers: {
Authorization: `Bearer ${accessToken}`
}
});
res.send("Authenticated successfully:" + JSON.stringify(userInfo.data, null, 2));
} catch (error) {
console.error("Error occurred during authentication:", error);
res.status(500).send("Failed to authenticate");
}
});
app.listen(PORT, () => {
console.log(`Server is running on http://localhost:${PORT}`);
});
Currently the returned token has the following properties:
{
"aud": "urn:microsoft:userinfo",
"iss": "http://******/adfs/services/trust",
"iat": 1709024014,
"exp": 1709027614,
"apptype": "Confidential",
"appid": "********",
"authmethod": "urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport",
"auth_time": "2024-02-27T07:02:54.533Z",
"ver": "1.0",
"scp": "openid",
"sub": "*******"
}
And the userInfo object only contains a sub
property.
{ "sub": "**********" }
What do I need to change to request those informations?
In the end, there was no need to get the USERINFO_ENDPOINT
.
Everything is included in the accessToken
.
The problem was the property resource: "urn:microsoft:userinfo"
. Deleting it allows to get email, first name and last name.
app.get("/login", (req: Request, res: Response) => {
const redirectUri = `${DOMAIN}/redirect`; // Redirect URI after authentication
const queryParams = new URLSearchParams({
response_type: "code",
client_id: CLIENT_ID,
redirect_uri: redirectUri,
scope: "openid"
});
res.redirect(`${AUTHORITY}/oauth2/authorize?${queryParams}`);
});
app.get("/redirect", async (req: Request, res: Response) => {
const code = req.query.code;
const data = {
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET,
grant_type: "authorization_code",
code: code,
redirect_uri: `${DOMAIN}/redirect`
};
try {
const response = await axios.post(TOKEN_ENDPOINT, data, {
headers: {
"Content-Type": "application/x-www-form-urlencoded"
}
});
const accessToken = response.data.access_token;
const decodedToken = ValidateToken(accessToken);
res.send(
"Welcome " +
decodedToken.unique_name +
" " +
decodedToken.family_name +
" " +
decodedToken.primarysid
);
} catch (error) {
console.error("Error occurred during authentication:", error);
res.status(500).send("Failed to authenticate");
}
});
For reference, below is the interface of the token:
interface AdfsJwt {
aud: string;
iss: string;
iat: number;
exp: number;
apptype: string;
appid: string;
authmethod: string;
auth_time: string;
ver: string;
scp: string;
family_name: string; // Last name
primarysid: string; // Email
unique_name: string; // First name
}