I have a backend in Nodejs using Axios for my API calls. I need to implement Azure Authentication to get a token so I followed the sample below:
https://learn.microsoft.com/en-us/azure/active-directory/develop/quickstart-v2-nodejs-webapp-msal?WT.mc_id=Portal-Microsoft_AAD_RegisteredApps
The sample uses express and has redirects to first get and authorization and then a token, I have been trying to find a sample with Axios however I couldn't find one.
This is what I have so far, the idea is using the result to get a token,any guidance is much appreciate it.
const msal = require('#azure/msal-node');
const REDIRECT_URI = "http://localhost:3000/";
const LOGIN = "https://login.microsoftonline.com/";
const config = {
auth: {
clientId: "12345678910",
authority: "https://login.microsoftonline.com/12345678910",
clientSecret: "Secret",
knownAuthorities: ["https://login.microsoftonline.com/12345678910"
]
}
};
const pca = new msal.ConfidentialClientApplication(config);
module.exports = {
async getAzureAdToken(){
try {
let instance = axios.create({baseURL: LOGIN});
const authCodeUrlParameters = {
scopes: ["user.read"],
redirectUri: REDIRECT_URI
};
pca.getAuthCodeUrl(authCodeUrlParameters).then((response) =>{
let url = response.substring(LOGIN.length);
instance.get(url).then((result) =>{
});
}).catch((error) => console.log(JSON.stringify(error)));
} catch (error) {
throw error
}
},
You could use client credentials flow to get access token with axios. Client credentials flow permits a web service (confidential client) to use its own credentials, instead of impersonating a user, to authenticate when calling another web service. In the client credentials flow, permissions are granted directly to the application itself by an administrator. We need to add application permissions in API Permission.
Test in Postman:
POST https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token
Content-Type: application/x-www-form-urlencoded
client_id=<client_id>
&scope=https://graph.microsoft.com/.default
&client_secret=<client_secret>
&grant_type=client_credentials
Code using Nodejs:
// Replace these values from the values of you app
const APP_ID = '[APP_ID/CLIENT_ID]';
const APP_SECERET = '[CLIENT_SECRET]';
const TOKEN_ENDPOINT ='https://login.microsoftonline.com/[TENANT_ID]/oauth2/v2.0/token';
const MS_GRAPH_SCOPE = 'https://graph.microsoft.com/.default';
const axios = require('axios');
const qs = require('qs');
const postData = {
client_id: APP_ID,
scope: MS_GRAPH_SCOPE,
client_secret: APP_SECERET,
grant_type: 'client_credentials'
};
axios.defaults.headers.post['Content-Type'] =
'application/x-www-form-urlencoded';
let token = '';
axios
.post(TOKEN_ENDPOINT, qs.stringify(postData))
.then(response => {
console.log(response.data);
})
.catch(error => {
console.log(error);
});
Related
I want to get Azure DevOps PAT list using REST API call. I'm using Azure Function App (JavaScript/NodeJS).
I want to get "PAT" list using the REST API. So I'm using the PAT List REST API, but I'm not able to get the list. I'm using the MSAL library for For Authentication. Using this MSAL library I'm able to get the authentication token although I'm unable to get "PAT List".
How we get "PAT List" ?
For more clarity I'm adding below our code. If I'm making any mistakes then anyone can rectify me.
const config = require('../config');
const rp = require('request-promise');
const msal = require('#azure/msal-node');
module.exports = async function (context, req) {
const clientId = 'config.DEFAULT_CLIENT_ID';
const clientSecret = 'config.DEFAULT_CLIENT_SECRET';
const tenantId = 'config.DEFAULT_TENANT_ID';
let authorityHostUrl = 'https://login.windows.net';
let authorityUrl = authorityHostUrl + '/' + tenantId;
const configuration = {
auth: {
clientId: clientId,
authority: authorityUrl,
clientSecret: clientSecret
}
};
// Create msal application object
const cca = new msal.ConfidentialClientApplication(configuration);
// With client credentials flows permissions need to be granted in the portal by a tenant administrator.
// The scope is always in the format "<resource>/.default"
const clientCredentialRequest = {
scopes: ["499b84ac-1321-427f-aa17-267ca6975798/.default"], // replace with your resource
};
const credentials = await cca.acquireTokenByClientCredential(clientCredentialRequest);
const tokenType = credentials.tokenType;
const token = credentials.accessToken;
const apiToken = `${tokenType} ${token}`; // 'Bearer <token>'
let url = `https://vssps.dev.azure.com/{organization}/_apis/tokens/pats?api-version=6.1-preview.1`;
const header = {
Authorization: `${apiToken}`
};
const result = await rp({
url: url,
json: true,
headers: header,
mode: 'cors',
cache: 'no-cache',
method: 'GET'
});
context.res = {
body: result
};
}
Output: After run the above code I'm getting the below result as HTML.
I'm not getting the proper response. Getting the above response as HTML view.
I want to use google pay API for passes with firebase cloud functions, but unfortunately, nodejs is bitterly missed in google-pay/passes-rest-samples and is not supported in the client libraries.
I was able to test the API in the PHP sample - that is my service account is up and linked to my merchant account, but I want to know how to use the API in nodejs:
1- How to get an access token and save a pass in the request call?
Tried the following but I'm always getting 401 status code:
a) Using google-auth-library-nodejs
// Create a new JWT client using the key file downloaded from the Google Developer Console
const auth = new google.auth.GoogleAuth({
keyFile: path.join(__dirname, 'serviceAccount.json'),
scopes: 'https://www.googleapis.com/auth/wallet_object.issuer',
});
const client = await auth.getClient();
const accessToken = (await client.getAccessToken()).token;
const result = (await axios.post(`https://walletobjects.googleapis.com/walletobjects/v1/loyaltyClass?strict=true`, payload,
{ headers: { Authorization: `Bearer ${accessToken}` } })
).data;
b) Using jsonwebtoken
const token = jwt.sign({ payload, typ: JWT_TYPE }, credentialJson.private_key,
{
algorithm: 'RS256',
audience: AUDIENCE,
issuer: SERVICE_ACCOUNT_EMAIL_ADDRESS,
});
Here is an example of how to achieve this with Node.js:
The relevant parts:
// Step 1: create a loyalty object
const loyaltyObject = await createLoyaltyObject();
// Step 2: define jwt claims
const claims = {
aud: 'google',
origins: [website],
iss: credentials.client_email,
typ: 'savetowallet',
payload: {
loyaltyObjects: [
{
id: loyaltyObject.id,
},
],
},
};
// Step 3: create and sign jwt
const token = jwt.sign(claims, credentials.private_key, { algorithm: 'RS256' });
I would like to create an azure function using NodeJS and authenticate to Graph APIs. Through my reading I know that I have to use client credentials flow. I am using this code as posted by:
const httpTrigger: AzureFunction = async function (context: Context, req: HttpRequest): Promise<void>
const APP_ID = [appId]';
const APP_SECERET = '[secret]';
const TOKEN_ENDPOINT ='https://login.microsoftonline.com/[tenantid]/oauth2/v2.0/token';
const MS_GRAPH_SCOPE = 'https://graph.microsoft.com/.default';
const axios = require('axios');
const qs = require('qs');
const postData = {
client_id: APP_ID,
scope: MS_GRAPH_SCOPE,
client_secret: APP_SECERET,
grant_type: 'client_credentials'
};
axios.defaults.headers.post['Content-Type'] =
'application/x-www-form-urlencoded';
axios
.post(TOKEN_ENDPOINT, qs.stringify(postData))
.then(response => {
context.res = {
body: response.data //JSON.stringify(w, null, 4)
};
})
.catch(error => {
console.log(error);
});
};
As mentioned in this post: How to get users from azure active directory to azure function
However this is not working as it's not even making a request to Azure. Is there something missing? Can't I use MSAL.JS to make server to server calls when am using Node or is it just for web based apps and won't work with azure functions?
Most of the examples am seeing are related to .Net and they're using bunch of nuget packages, etc.. Isn't what I need supported in JavaScript azure functions?
Thanks.
I don't know why did you say it's not even making a request to azure, I test it with almost same code with yours and it work fine. I provide details of my steps as below for your reference.
1. I create a type script function in VS code (do not forget declare require in the second line of my code), my function code show as:
import { AzureFunction, Context, HttpRequest } from "#azure/functions"
declare var require: any
const httpTrigger: AzureFunction = async function (context: Context, req: HttpRequest): Promise<void> {
const APP_ID = 'xxxxxx';
const APP_SECERET = 'xxxxxx';
const TOKEN_ENDPOINT ='https://login.microsoftonline.com/xxxxxx/oauth2/v2.0/token';
const MS_GRAPH_SCOPE = 'https://graph.microsoft.com/.default';
const axios = require('axios');
const qs = require('qs');
const postData = {
client_id: APP_ID,
scope: MS_GRAPH_SCOPE,
client_secret: APP_SECERET,
grant_type: 'client_credentials'
};
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
axios
.post(TOKEN_ENDPOINT, qs.stringify(postData))
.then(response => {
console.log('=====below is response====');
console.log(response.data);
console.log('=====above is response====');
context.res = {
body: response.data
};
})
.catch(error => {
console.log(error);
});
};
export default httpTrigger;
2. I install axios and qs modules by the command:
npm install axios
npm install qs
3. To start the function, I ran the command:
npm install
npm start
4. After request the function, I get the result as:
My goal is to consume an API which has already been deployed with nopCommerce (I do not have dev access to the server - I am just a user). There is a sample client application here, but the code is in C#. I have a webapp deployed on an Azure server using node.js. The API uses the OAuth 2.0 Authorization Code grant type.
I did a bit of Googling and it appears that client_credentials is typically used for this type of server to server flow:
How does 2-legged oauth work in OAuth 2.0?
Using OAuth for server-to-server authentication?
There is also an answer here which suggests that I can manually retrieve a token and then store it on the server. This is what I'm currently doing while testing my code.
I also found this answer which appears to be asking the same question. Like the author of that post, I am able to get a token via Postman, but my node.js code fails.
OAuth2.0 for nopCommerce
I wrote a minimal example in node.js here.
import { config } from 'dotenv';
import * as path from 'path';
import fetch from 'cross-fetch';
const ENV_FILE = path.join(__dirname, '.env');
const loadFromEnv = config({ path: ENV_FILE });
export async function getCodeUrl() {
const params = {
client_id: <CLIENT_ID>,
redirect_uri: 'http://example.com',
response_type: 'code',
};
console.log(params);
const url = new URL(`http://example.com/OAuth/Authorize`);
Object.keys(params).forEach(( key ) => url.searchParams.append(key, params[key]));
const res = await fetch(url.href, { method: 'GET' });
return res;
}
export async function getToken(code: string) {
const url = new URL(`http://example.com/api/token`);
const options = {
form: {
client_id: <CLIENT_ID>,
client_secret: <CLIENT_SECRET>,
code,
grant_type: 'authorization_code',
redirect_ui: 'http://example.com',
},
headers: { 'content-type': 'application/x-www-form-urlencoded' },
method: 'POST',
};
console.log(options);
const res = await fetch(url.href, options);
console.log('res', res);
return res;
}
const test = async () => {
const codeUrlString = (await getCodeUrl()).url;
const code = (new URL(codeUrlString).searchParams.get('code'));
if (code) {
console.log('code', code);
const tokenResponse = await getToken(code);
console.log('token res', tokenResponse);
}
};
test();
I am successfully able to retrieve the authorization code, but when I use that in a POST request to get a token, I get this error:
{ error: 'invalid_client' }
How to implement OAuth 2 Circuit REST API for Bots? To use the client_id and client_secret. Thank you.
See https://circuit.github.io/oauth.html#client_credentials on the HTTP request to get the token. You can manually perform the /oauth/token request to get a token, or use any OAuth 2.0 library. The perform regular HTTP GET/POST requests using this OAuth token.
Here is an example that uses simple-oauth2 to get the token and then node-fetch to get the conversations.
const simpleOauth2 = require('simple-oauth2');
const fetch = require('node-fetch');
const DOMAIN = 'https://circuitsandbox.net';
const credentials = {
client: {
id: '<client_id>',
secret: '<cient_secret>'
},
auth: {
tokenHost: DOMAIN
}
};
// Initialize the OAuth2 Library
const oauth2 = simpleOauth2.create(credentials);
(async () => {
try {
const { access_token: token } = await oauth2.clientCredentials.getToken({scope: 'ALL'})
console.log('Access Token: ', token);
const convs = await fetch(`${DOMAIN}/rest/conversations`, {
headers: { 'Authorization': 'Bearer ' + token },
}).then(res => res.json());
console.log('Conversations:', convs);
} catch (err) {
console.error(err);
}
})();