cancel
Showing results for 
Search instead for 
Did you mean: 

Get OAuth2 access token via Javascript

SAPWayneSG
Participant
0 Kudos

I am using below code to fetch the token from Event Mesh server, it succeeded with no error.

However, this token is incorrect, the length is only 1601, and the correct token length shall be 1869.

This causes the next code block of publishing an event to SAP event mesh failed with unauthorized error message.

Did anyone succeed to get a correct token before? Please help, thanks.

const fetch = require('node-fetch');

async function getEMAccessToken() {
    const EMTokenURL = 'your-token-url';
    const EMClientID = 'your-client-id';
    const EMClientSecret = 'your-client-secret';

    const credentials = Buffer.from(`${EMClientID}:${EMClientSecret}`).toString('base64');

    const response = await fetch(EMTokenURL, {
        method: 'POST',
        headers: {
            'Content-Type': 'application/x-www-form-urlencoded',
            'Authorization': `Basic ${credentials}`
        },
        body: 'grant_type=client_credentials'
    });

    if (!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`);
    }

    const data = await response.json();
    return data.access_token;
}
Dinu
Active Participant
0 Kudos

Why do you say that the token has to be of length 1869?

gregorw
Active Contributor
0 Kudos

If you're using CAP why to you want to establish the connection manually. Have you followed the documentation:

https://cap.cloud.sap/docs/guides/messaging/#sap-event-mesh

?

SAPWayneSG
Participant
0 Kudos

Hi Dinu,

Thanks for your question, While I am testing the code above, I am able to get the access token, however, in next step to publish an event to SAP Event Mesh, I always got "Unauthorized" error.

After almost several hours struggling, I finally decide to write .NET desktop application to verify the logic, and it works. Then I use the access token I have retrieved in .NET application and paste it to my Javascript code block for publishing event, it also works fine.

So I just do a comparison between the access token from Javascript code and .NET Application, then I find the length is different. Actually the first 185 characters of the access token are same.

SAPWayneSG
Participant
0 Kudos

Hi Gregor, thanks for your comment, the manual connection is for a special use case.

And I also try to follow the cap document on event mesh, but I encounter some issue on deploying the project onto Cloud Foundry, once I settle the deployment issue, I will try that again.

gregorw
Active Contributor
0 Kudos

Hi Jin,

please use comments when the part you're posing isn't a solution to the problem.

Maybe you describe us this "special use case" and we can help to find alternative solution options.

Best Regards
Gregor

Dinu
Active Participant

Try decoding the tokens perhaps using JSON Web Tokens - jwt.io and check what is different between the payloads of the tokens.

Warning: Tokens are credentials. You should be aware of the risks in sharing these with external sites.

Accepted Solutions (1)

Accepted Solutions (1)

martinstenzig
Contributor
0 Kudos

Don't know if it makes a difference, but I usually attach then credentials to the body, not the header...

 // specify form parameters
      const formParams = new URLSearchParams()
      formParams.append('grant_type', 'client_credentials')
      formParams.append('client_id', '[clientIdValue]')
      formParams.append('client_secret', '[client secret value]')

      // Assemble the post options
      const postOptions = {
        method: 'POST',
        headers: {
          'Content-type': 'application/x-www-form-urlencoded'
        },
        body: formParams
      }

      // console.log('Post options: ', tokenUrl, post_options);
      fetch(tokenUrl, postOptions)
        .then(res => res.json())
...
SAPWayneSG
Participant
0 Kudos

Hi Martin,

Thanks for your suggestion, I follow your example, below is my revised codes. However, after testing, the result is same, it will retrieve an incorrect access token string of 1601 length.

Note: Below codes block is for reference, it does not solve the token issue.

async function getEMAccessToken() {

const EMTokenURL = tokenUrl;

const EMClientID = clientId;

const EMClientSecret = clientSecret;

// specify form parameters

const formParams = new URLSearchParams();

formParams.append('grant_type', 'client_credentials');

formParams.append('client_id', EMClientID);

formParams.append('client_secret', EMClientSecret);

// Assemble the post options

const postOptions = {

method: 'POST',

headers: {

'Content-type': 'application/x-www-form-urlencoded'

},

body: formParams

};

const response = await fetch(EMTokenURL, postOptions);

if (!response.ok) {

throw new Error(`HTTP error! status: ${response.status}`);

}

const data = await response.json();

return data.access_token;

}

Answers (1)

Answers (1)

SAPWayneSG
Participant
0 Kudos

Dear all,

I finally find the root cause of my problem. It's purely my own mistake. Sorry for the confusion caused.

When I wrote the codes in the Javascript, I copied the clientid and clientsecret incorrectly. In fact, I copied the ClientID and ClientSecret of Cloud Foundry Authentication instead of Event Mesh.

When I created the testing project with .NET, I unconsciously used the correct id & secret as I reused the encrypted strings for clientid and clientsecret in a config file from another project.

A big thank you to Dinu, Gregor, and Martin for sharing your insightful comments. Because of your comments, I start to think it would be my own problem instead of some weird behavior from the system. Lesson learned from this experience:

  1. The length of access token from Cloud Foundry Authentication is 1601, and for Event Mesh it's 1869.
  2. Back to the original purpose (to fetch the OAuth2 access token in Javascript), below are the workable code block.

Solution 1:

// Solution 1 from Martin Stenzig
async function getEMAccessToken() {
const EMTokenURL = tokenUrl;
const EMClientID = clientId;
const EMClientSecret = clientSecret;
// specify form parameters
const formParams = new URLSearchParams();
formParams.append('grant_type', 'client_credentials');
formParams.append('client_id', EMClientID);
formParams.append('client_secret', EMClientSecret);
// Assemble the post options
const postOptions = {
method: 'POST',
headers: {
'Content-type': 'application/x-www-form-urlencoded'
},
body: formParams
};
const response = await fetch(EMTokenURL, postOptions);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
return data.access_token;
}

Solution 2:

// Alternative solution from mine
async function getEMAccessToken() {
    const EMTokenURL = 'your-token-url';
    const EMClientID = 'your-client-id';
    const EMClientSecret = 'your-client-secret';

    const credentials = Buffer.from(`${EMClientID}:${EMClientSecret}`).toString('base64');

    const response = await fetch(EMTokenURL, {
        method: 'POST',
        headers: {
            'Content-Type': 'application/x-www-form-urlencoded',
            'Authorization': `Basic ${credentials}`
        },
        body: 'grant_type=client_credentials'
    });

    if (!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`);
    }

    const data = await response.json();
    return data.access_token;
}<br>

Thanks Martin for sharing the codes, I have quoted them above, it could be a good reference for others who are interested in this topic.

Thanks Gregor for reminding me of the CAP way of messaging handling which I will try later and post another question on it. For special use case, the current codes works fine, but I will rethink it and may consult you again if I encounter issue.

Thanks Dino for sharing the online tool of "JSON Web Tokens - jwt.io", it will be useful for my future exploration.

Last I am not sure what shall I do for this question, shall I delete this question? In fact, my initial assumption (I have encountered an weird behavior from system) is incorrect. If it still offer some value for others, I will leave it there. To consider the relevance to the topic of this question, I may accept Martin's answer as the best answer. I need some advice from the admin or regular members in this community.