ADFS2016 oauth2 confidential app missing user informations

45 Views Asked by At

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?

2

There are 2 best solutions below

0
Victor On BEST ANSWER

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
}
1
rbrayb On

ADFS is hard-coded to only return "sub" for userinfo.

You can't add other attributes.