0

I'm currently working on a project with multiple interconnected HTTP APIs and I'm adding authentication. The infrastructure I'm working with has a Azure Active Directory 2025 and an SSO accessed through OAuth2.

I'm trying to simplify Authentication between my HTTP APIs so here's what I've come up with:

All Request between applications have an HTTP header listing security groups in the form of

X-SecGroup: groupone,grouptwo,..."

They use it to authorize their request internally and I won't get into this.

I have an NGINX reverse proxy forwarding requests to those applications. All comminucations go through that proxy. I would like that proxy to get a user request containing the user's OAuth2 token, authorize it through OAuth and somehow use it to contact the AD and get the user's security groups and add that X-SecGroup header to every request it sends downstream.

Is there some way to do that?

If getting the group is impossible and the only way is to check against a list of known security groups, it's okey too :)

Feel free to explain how I'm completely off the mark if I am, I'm still a noob in CyberSec...

1 Answer 1

1

Ideally in OAuth you should issue claims like the user's groups to access tokens so that they are readily available to APIs to use for authorization:

  • You assign a client a custom scope like orders, to represent an area of data.
  • You create a custom claim like groups and associate it to the scope.
  • When the authorization server issues access tokens with the scope, it reads the user's account, retrieves group values and issues them as claims.

ENTRA ID

Entra ID requires vendor specific logic that adds complexity. If you try to issue group claims, I believe that Entra ID returns group object IDs as explained in this stack overflow answer.

To get group names you may need to send an access token to the Graph endpoint at https://graph.microsoft.com/v1.0/groups. You then get a response with items such as those listed below:

{
  "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#groups",
  "value": [
    {
      "id": "ae0796f2-0b56-4511-8bd7-f86dedf6e2d7",
      "createdDateTime": "2025-07-22T07:26:56Z",
      "description": "Members of the DevOps team",
      "displayName": "devops"
    }
  ]
}

It is a little tricky though, since Graph requires its own type of access token, whereas you usually need a different access token for your own APIs. To get a Graph access token you are likely to need to use the On Behalf Of Flow. The following Node.js code demonstrates the approach, where an API swaps the incoming access token for a new one:

const formData = new URLSearchParams();
formData.append('grant_type', 'urn:ietf:params:oauth:grant-type:jwt-bearer');
formData.append('client_id', this.configuration.graphClient.clientId);
formData.append('client_secret', this.configuration.graphClient.clientSecret);
formData.append('assertion', accessToken);
formData.append('scope', 'openid profile');
formData.append('requested_token_use', 'on_behalf_of');

const options = {
    url: this.configuration.tokenEndpoint,
    method: 'POST',
    data: formData,
    headers: {
        'content-type': 'application/x-www-form-urlencoded',
        'accept': 'application/json',
    },
};

const response = await axios.request(options);
const graphAccessToken = response.data.access_token;

Finally, you need an app registration in Entra ID to represent the component that makes the Graph API groups request. That entry needs the GroupMember.Read.All permission and also provides the client ID and secret for the above OBO request.

enter image description here

SUMMARY

I suggest that you experiment to get the groups from Entra ID and then decide where to put the code. In NGINX this would be a subrequest which can be tricky to implement. I would try to avoid sending a secure value like groups in plain HTTP headers, since it allows an exploit to send its own groups. Instead, aim for APIs to receive the groups either in the access token (preferred) or by calling the Graph endpoint.

Sign up to request clarification or add additional context in comments.

5 Comments

It is Entra Id.
So, if we imagine we have 3 types of users "Administrators, Editors and Readers", I can make 3 different claims like 'User is part of administrator" and add headers for the one that passes right?
I updated my answer - it may be tricky in Entra ID though, as my answer indicates.
Ok I understand now, but i see what I'm trying to do might be bad practice in terms of security.
Thank you, your anwser helped me a lot :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.