Initialise Azure Application Client in TypeScript - javascript

New to Typescript and still getting used to Microsoft Azure so please excuse the basic question.
I have created an Enterprise Application which should be able to log into the Graph API and read a user profile. I have the client id/secret , tenant id but I need to know how to initialise this client within TypeScript.
Am i supposed to initialise a GraphClient or is there a a generic Client I can use?
A link to a tutorial/example or documentation on how to do this would be amazing.
For context I want to be able to write one function to initialise the client and subsequently write the query- all the docs talk about multiple files which I cannot utilise because I am writing this as a third party integration.
I have found this but it seems very complex and I can't really follow it.
Is there a typescript equivalent of
client_credential = ClientSecretCredential(tenant_id, client_id, client_secret)
client = GraphClient(credential=self.client_credential,
scopes=['https://graph.microsoft.com/.default']
)

This is the way I've managed to do it. I'm bounded by using an extremely old version of the microsoft graph module unfortunately.
const qs = require('qs');
const MicrosoftGraphClient = require('#microsoft/microsoft-graph-client#1.0.0');
const axios = require('axios#0.27.2');
const getToken = async () => {
try{
const response = await axios.post(
`https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/token`,
qs.stringify(
{
client_id : clientId,
client_secret: clientSecret,
scope: 'https://graph.microsoft.com/.default',
grant_type: 'client_credentials'
}
))
let tokenSet = response.data;
return tokenSet.access_token;
} catch (error){
console.log(error)
};
}
var client = MicrosoftGraphClient.Client.init({
authProvider: async (done) => {
const token = await getToken()
done(null, token);
}
});

Related

How to get Auth Token of Azure to create azure resources programmatically

I want to create azure resources but I am having an issue while generating the token credential for creating such resources.
The following is the way to create azure postgres SQL but I need to Pass the credentials
But I don't know how to generate that token programitaillcay.
I need help for this.
const msRestAzure = require('ms-rest-azure');
const PostgreSQLManagementClient = require('azure-arm-postgresql');
const subscriptionID = '<subscription id>';
const resourceGroup = '<resource group name>';
const serverName = '<server name>'; // must be globally unique
msRestAzure.interactiveLogin().then((credentials) => {
let client = new PostgreSQLManagementClient(credentials, subscriptionID);
return client.servers.createOrUpdate(resourceGroup, serverName, {
location: 'eastus',
properties: {
createMode: 'Default',
administratorLogin: 'postgres',
administratorLoginPassword: 'F00Bar!!'
}
});
}).then((server) => {
console.log('Server:');
console.dir(server, {depth: null, colors: true});
}).catch((err) => {
console.log('An error ocurred');
console.dir(err, {depth: null, colors: true});
});
Does anyone know how to generate it? and using what? It's a signed token I guess using Client Id and tenant ID But how to generate it.
There's no documentation provided to generate it programitially. Is there any way?
interactiveLogin() will provide a link and a code that will allow the user to authenticate from a browser.
When using the Node.js SDK programmatically, there are 2 methods.
1)You could use your username and password to authenticate with the API using your Azure account. It's not recommended because it requires a very high degree of trust in the application, and carries risks which are not present in other flows.
const Azure = require('azure');
const MsRest = require('ms-rest-azure');
MsRest.loginWithUsernamePassword(process.env.AZURE_USERNAME, process.env.AZURE_PASSWORD, (err, credentials) => {
if (err) throw err;
let client = new PostgreSQLManagementClient(credentials, subscriptionID);
// ...
});
2)You may want to use service principal authentication rather than providing your account credentials. It is based on service principal without user account. First, create service principal in Azure portal.
const Azure = require('azure');
const MsRest = require('ms-rest-azure');
MsRest.loginWithServicePrincipalSecret(
'clientId/appId',
'client-secret',
'tenantId',
(err, credentials) => {
if (err) throw err
let client = new PostgreSQLManagementClient(credentials, subscriptionID);
// ...
}
);
For more detail about JavaScript authentication samples using ms-rest-azure library, see here.
Update:
If using service principal, try to add Azure OSSRDBMS Database application permission. Navigate to Azure AD > your app > API permission. And remember to grant admin consent for your tenant.

How do I complete authentication using the Spotify Web API

I'm trying to generate an access token to access the web player of the SpotifyWebApi and play music in the browser. Even after trying several things, including reading Spotify's authorization documentation for the Authorization Code Flow, I'm still stuck and I can't get an access code. The documentation outlines a 3-step process. Only the first part is working for me, and I'm stuck in the 2nd step. (Spotify Docs: https://developer.spotify.com/documentation/general/guides/authorization-guide/)
Here's what I've done:
Step 1:
export const authEndpoint = "https://accounts.spotify.com/authorize";
const redirectUri = "http://localhost:3000/";
const clientID = "[redacted]";
const clientSecret = "[redacted]";
const scopes = [
"user-library-read",
"user-library-modify",
"user-read-playback-state",
"user-read-currently-playing",
"user-read-recently-played",
"user-top-read",
"user-modify-playback-state"
];
export const loginUrl = `${authEndpoint}?client_id=${clientID}&response_type=code&redirect_uri=${redirectUri}&scopes=${scopes.join(
"%20"
)}&show_dialog=true`;
const ACCESS_CODE = getCodeFromUrl();
Step 2:
const POST_OBJECT_BODY = {
grant_type: "authorization_code",
code: ACCESS_CODE,
redirect_uri: redirectUri,
client_id: clientID.toString("base64"),
client_secret: clientSecret.toString("base64"),
};
fetch("https://accounts.spotify.com/api/token", {
mode: "no-cors",
method: "POST",
body: JSON.stringify(POST_OBJECT_BODY),
}).then((response) => {
console.log("Response: ", response);
});
I had to add the "no-cors" part because I was getting CORS errors.
I've tried other authentication methods and they seem to work, but I'm not getting a proper access token. I say this because I'm unable to play the music - it kept saying "Permissions missing" despite me having the proper scopes.
Any help with the above will be appreciated. Thank you!
Just a small remark, the redirect uri you are using in step 2 has to be encoded.

Discord: Get User by Id

I'm trying to create a web application to manage the users of my Discord server. In my database, I have stored only the users' ids.
I tried to use the discord.js API, but from what I've understood it requires a discord bot to do that. That's not what I want. I would like to retrieve the user's information from my frontend, even by calling a backend function, but without having a discord bot which is always online. In other words, I need something simpler.
I would like to request users' information by using only the id. Which is the best way to do that in JavaScript?
You can use the Discord API.
First, create a Discord application here. Once you've done that, click 'Bot' on the sidebar and create a bot for that application. There, you'll see a section called 'Token' under the bot username. Copy this and store it somewhere secure. It is important to never share your token. If you do, you should regenerate it to prevent abuse.
You can then use the Get User endpoint (/users/{user.id}/) to retrieve the user for an ID. This should be done by the backend as it involves authenticating with the bot token.
Using the API directly
Here is a minimal example of how you would fetch a user by their ID using the Discord API using Node.js:
const fetch = require('node-fetch')
// You might want to store this in an environment variable or something
const token = 'YOUR_TOKEN'
const fetchUser = async id => {
const response = await fetch(`https://discord.com/api/v9/users/${id}`, {
headers: {
Authorization: `Bot ${token}`
}
})
if (!response.ok) throw new Error(`Error status code: ${response.status}`)
return JSON.parse(await response.json())
}
The response would be something like this:
{
"id": "123456789012345678",
"username": "some username",
"avatar": null,
"discriminator": "1234",
"public_flags": 0,
"banner": null,
"banner_color": null,
"accent_color": null
}
Using a library
Alternatively, you may be able to use a Discord library to do this instead. The following examples also handle rate limits.
#discordjs/rest + discord-api-types
const {REST} = require('#discordjs/rest')
const {Routes} = require('discord-api-types/v9')
const token = 'YOUR_TOKEN'
const rest = new REST().setToken(token)
const fetchUser = async id => rest.get(Routes.user(id))
The result would be the same JSON as described above.
For TypeScript users:
import type {RESTGetAPIUserResult, Snowflake} from 'discord-api-types/v9'
const fetchUser = async (id: Snowflake): Promise<RESTGetAPIUserResult> =>
rest.get(Routes.user(id)) as Promise<RESTGetAPIUserResult>
discord.js
When I first posted this answer, #discordjs/rest didn't exist yet.
const {Client} = require('discord.js')
const token = 'YOUR_TOKEN'
const client = new Client({intents: []})
client.token = token
const fetchUser = async id => client.users.fetch(id)
The result of fetchUser would be a discord.js User object.
Something you can do is
let user = message.guild.cache.get('id');
(modified by #cherryblossom)

Spotify PKCE code_verifier was incorrect

I was excited to hear that I can now use the Spotify web API without having a backend application via PKCE. Unfortunately, I seem to have some sort of misunderstanding and have been unable to get it to work.
I am likely making some minor mistake along the way, but I did it once to no avail and I wiped the slate clean and tried again but still without luck. From this I gather that I must be misunderstanding the documentation.
I will explain what I am doing and hopefully someone here can point out what I'm missing or doing wrong. I'm assuming I have a fundamental conceptual misunderstanding.
I first generate a cryptographically random string using an npm package called crypto-random-string. I store that in the browser's local storage before using js-sha256 to hash it and then using another npm package called base64url to encode it.
let verifier = cryptoRandomString({length: 50})
window.localStorage.setItem('verifier', verifier)
let params = {
client_id: '[MY CLIENT ID]',
response_type: 'code',
redirect_uri: 'http://localhost:3000/callback',
code_challenge_method: 'S256',
code_challenge: base64url(sha256(verifier))
}
let endpoint = new URL('https://accounts.spotify.com/authorize');
endpoint.search = new URLSearchParams(params);
window.location = endpoint.toString();
From here, I redirect to the /authorize endpoint with the proper url parameters. I have gotten this far successfully and then been redirected accordingly to my provided redirect_uri, where I grab the given code from the url parameters.
At this point, I try the fetch to the /api/token endpoint with the client_id, grant_type, the code I got from the url params, my redirect_uri, and the locally stored code_verifier.
let params = new URLSearchParams(window.location.search);
console.log(params.get('code'));
let newParams = {
client_id: '[MY CLIENT ID]',
grant_type: 'authorization_code',
code: params.get('code'),
redirect_uri: 'http://localhost:3000/callback',
code_verifier: window.localStorage.getItem('verifier')
}
let endpoint = new URL('https://accounts.spotify.com/api/token');
endpoint.search = new URLSearchParams(newParams);
fetch(endpoint.toString(), {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}).then(data => data.json()).then(console.log)
At this point, after both of my attempts I received the error:
{ error: "invalid_grant", error_description: "code_verifier was incorrect" }
Is there anything that I am obviously doing wrong? The error leads me to believe I'm doing something wrong as far as the actual generation of the code_verifier, but I am at a loss to what that issue may be.
Someone on the Spotify forum pointed me to this answer. Not sure why exactly, but doing the encoding the following way does work:
async function sha256(plain) {
const encoder = new TextEncoder()
const data = encoder.encode(plain)
return window.crypto.subtle.digest('SHA-256', data)
}
function base64urlencode(a){
return btoa(String.fromCharCode.apply(null, new Uint8Array(a))
.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '')
}
const hashed = await sha256(verifyCode)
const codeChallenge = base64urlencode(hashed)
Previous answers and comments, in addition to OP, has documented most information needed so I will only add what helped me:
The verifier itself most be encoded as a Base64-URL.
Pseduo-code (as I myself code in C#):
verifier = Base64UrlEncode(GetRandomString(length: 50))
challenge = Base64UrlEncode(HashWithSha256(verifier))

CF Connect to the cloud controller

I use the following lib to connect to the cloud controller
https://github.com/prosociallearnEU/cf-nodejs-client
const endpoint = "https://api.mycompany.com/";
const username = "myuser";
const password = "mypass";
const CloudController = new (require("cf-client")).CloudController(endpoint);
const UsersUAA = new (require("cf-client")).UsersUAA;
const Apps = new (require("cf-client")).Apps(endpoint);
CloudController.getInfo().then((result) => {
UsersUAA.setEndPoint(result.authorization_endpoint);
return UsersUAA.login(username, password);
}).then((result) => {
Apps.setToken(result);
return Apps.getApps();
}).then((result) => {
console.log(result);
}).catch((reason) => {
console.error("Error: " + reason);
});
I try to run it against our API and its not working and Im not getting no error message in the console, what it can be ?
where does the space/org is handled here ? since when I connect from the cli it ask me to which space/org I want to connect...
Im able to login via the CLI, just from the code I cant, any idea what is missing here?
The issue it when I run it I dont get any error that can help to understand what is the root cause
I cloned the original git repository and modified some methods to support proxy. Please note that I modified just some methods to get the sample code working, but a complete refactor of the package is needed.
Basically what you have to do is to add a proxy parameter before calling the request method (this is done throughout the package, so several modifications are needed), for example this is for one of the methods in the Organization.js file:
getSummary (guid) {
const url = `${this.API_URL}/v2/organizations/${guid}/summary`;
const proxy = `${this.API_PROXY}`;
const options = {
method: "GET",
url: url,
proxy: proxy,
headers: {
Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}`
}
};
return this.REST.request(options, this.HttpStatus.OK, true);
}
You can find my changes in the git repository below:
https://github.com/adasilva70/cf-nodejs-client.git
I have also created a new sample below. This sample lists all organizations for a user, gets the first organization returned and lists its spaces. You can modify the code to provide a similar functionality that cf login provides (allow you to select an organization then a space).
const endpoint = "https://api.mycompany.com/";
const username = "youruser";
const password = "yourpassword";
const proxy = "http://proxy.mycompany.com:8080";
const CloudController = new (require("cf-nodejs-client")).CloudController(endpoint, proxy);
const UsersUAA = new (require("cf-nodejs-client")).UsersUAA;
const Apps = new (require("cf-nodejs-client")).Apps(endpoint, proxy);
const Orgs = new (require("cf-nodejs-client")).Organizations(endpoint, proxy);
CloudController.getInfo().then((result) => {
console.log(result);
UsersUAA.setEndPoint(result.authorization_endpoint, proxy);
return UsersUAA.login(username, password);
}).then((result) => {
//Apps.setToken(result);
//return Apps.getApps();
Orgs.setToken(result);
return Orgs.getOrganizations();
}).then((result) => {
console.log(result);
org_guid = result.resources[1].metadata.guid;
return Orgs.getSummary(org_guid);
}).then((result) => {
console.log(result);
}).catch((reason) => {
console.error("Error: " + reason);
});
I have done just minor tests to make sure the sample works, so use carefully. Also, the changes will only work for a case where proxy is needed now.
The first thing that strikes me on the library's github site is the warning:
Note: This package is not ready for a production App yet.
It also seems that the project is not being maintained as there are a number of tickets ooened that are quite a few months old that don't have a response.
Anyway, to figure out why the library is not working and producing no error message, I would check out the library source code and add some console logging statements, probably starting with the HttpUtils. For example:
requestWithDefaults(options, function (error, response, body) {
console.log("requestWithDefaults error: ", error)
console.log("requestWithDefaults response: ", response)
console.log("requestWithDefaults body: ", body)
...
}
Alternatively, you could try debugging the code by adding breakpoints to the requestWithDefaults and other key places in the library, using the nodejs debugger.
You could also try debugging the network calls similar to this how to monitor the network on node.js similar to chrome/firefox developer tools?
To understand how to use the library, I would take a look into the tests folder and look for a test that is similar to your use case. There are a reasonable amount if tests that look useful in the test/lib/model/cloudcontroller folder.
As for the question about spaces, I have found an example where you can pass in a space guid to return apps for that space guid.
CloudFoundrySpaces.getSpaceApps(space_guid, filter).then( ... )
I'm assuming the call you are using App.getApps() will return Apps for all spaces/organizations.

Categories

Resources