How to generate token for client_assertion without certificates?

DevanshAgarwal-0149 0 Reputation points
2024-07-19T11:14:11.81+00:00

We have an app registration which is connected to an external API. We have to use this API in our Azure Data factory. For this purpose, till now we were generating client secrets and generating tokens (in Azure Data Factory) from this URL - login.microsoftonline.com/{tenant}/oauth2/v2.0/token. Now to eliminate the use of secrets, we have created a managed identity and linked to our App registration using federated credentials. Now we have to generate tokens using this user assigned managed identity. However, in the data factory when we are trying to generate the tokens using the Method "POST", the body requires us to add grant_type even on using User Assigned Managed identity for authentication. This requires us to add a client_assertion in the body as well but we are not sure how to proceed with that?

We cannot generate certificates for the managed identity as we have to remove dependency on keys, secrets and certificates. We were able to write an azure function that generates the token by the following code -

const jwt = require('jsonwebtoken');
const { DefaultAzureCredential, ManagedIdentityCredential } = require('@azure/identity');

module.exports = async function (context, req) {
    context.log('JavaScript HTTP trigger function processed a request.');

    const clientId = req.query.clientId;
    const resource = req.query.resource;

    if (!clientId || !resource) {
        context.res = {
            status: 400,
            body: "Please pass clientId and resource on the query string"
        };
        return;
    }

    try {
        const credential = new ManagedIdentityCredential(clientId);
        const tokenResponse = await credential.getToken(resource);
        
        context.res = {
            status: 200,
            body: tokenResponse.token
        };
    } catch (error) {
        context.res = {
            status: 500,
            body: `Error acquiring token: ${error.message}`
        };
    }
};

And used the token generated in the following POST call -

@concat('grant_type=client_credentials
&scope=<Survey-Scope-Here>/.default&client_id=', activity('Get Client ID').output['value'],'&client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer&client_assertion=<Token-here>')

But on passing this code into the body of the POST request in assertion, an error is generated -

"error":"invalid_client","error_description":"AADSTS700211: No matching federated identity record found for presented assertion issuer 'https://sts.windows.net/<ID-HERE>/'. Please check your federated identity credential Subject, Audience and Issuer against the presented assertion.

We cannot generate private keys for signing of a JWT token. How can I resolve this error?

Thank you!

Azure Data Factory
Azure Data Factory
An Azure service for ingesting, preparing, and transforming data at scale.
10,139 questions
Azure App Service
Azure App Service
Azure App Service is a service used to create and deploy scalable, mission-critical web apps.
7,364 questions
0 comments No comments
{count} votes

1 answer

Sort by: Most helpful
  1. Amira Bedhiafi 19,706 Reputation points
    2024-07-21T17:56:21.48+00:00

    You may try with managed identities with ADF an Azure Function but as a perquisite you may need to verify if the ADF has a system-assigned or user-assigned managed identity configured, and grant it the necessary permissions to access both the external API and the Azure Function App.

    Then, create an Azure Function that generates the token using the managed identity. Deploy this function and test it to ensure it correctly provides the token when called.

    In ADF, set up a web activity to call this Azure Function and retrieve the token. Once you have the token, use it in the body of your POST request to the external API, formatted as follows:

    • URL: https://<external-api-url>
    • Method: POST
    • Headers:
    {
        "Content-Type": "application/x-www-form-urlencoded"
    }
    
    • Body :
    {
        "grant_type": "client_credentials",
        "scope": "<Survey-Scope-Here>/.default",
        "client_id": "@{activity('Get Client ID').output['value']}",
        "client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
        "client_assertion": "@{variables('token')}"
    }