Look at my code, what am I doing wrong? I need to get https://graph.microsoft.com/v1.0/users/${uniqueName}/manager. But the request fails
But when I try to execute the https://graph.microsoft.com/v1.0/${uniqueName} query, everything goes well. What to fix so that the https://graph.microsoft.com/v1.0/users/${uniqueName}/manager request is successful?
fastify.post('/login', {
preHandler: (request, _, next) => {
if (!request.body || !request.body.username || !request.body.password) {
const error = new Error('Credentials are missing');
error.statusCode = 400;
return next(error);
}
return next();
},
}, async (request, reply) => {
const { username, password } = request.body;
const userData = await fastify.helpers.authentication.getUserTokens(username, password, azureConfig.CLIENT_SCOPE);
await replyWithTokens(fastify, reply, userData);
});
And next
const getUserTokens = async (username, password, scope) => {
const authUrl = `https://login.microsoftonline.com/${azureConfig.TENANT_NAME}/oauth2/v2.0/token`;
const body = {
client_id: azureConfig.CLIENT_ID,
client_secret: azureConfig.CLIENT_SECRET,
grant_type: 'password',
password,
scope,
username,
};
const authResponse = await fetch(authUrl, {
body: new URLSearchParams(body).toString(),
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
method: 'POST',
});
if (!authResponse.ok) {
fastify.helpers.error.throwError(422, 'Authentication failed');
}
const result = await authResponse.json();
const decodedData = jwt.decode(result.access_token);
const uniqueName = String(decodedData.unique_name || '').toLowerCase();
const name = String(decodedData.upn || uniqueName).toLowerCase();
const agentAttributes = {};
if (!uniqueName) {
fastify.helpers.error.throwError(400, 'Unique name not found');
}
let recheckSan = true;
let san = name.split('#').shift();
let agent = await fastify.db.models.Agent.findOne({
where: { uniqueName },
});
let radId = '';
const graphAuthResponse = await fetch(authUrl, {
body: new URLSearchParams({
...body,
scope: 'email openid profile https://graph.microsoft.com/User.Read',
}).toString(),
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
method: 'POST',
});
if (graphAuthResponse.ok) {
const graphAuthResult = await graphAuthResponse.json();
const { access_token: graphAccessToken = '' } = graphAuthResult;
// eslint-disable-next-line max-len
const graphResponse = await fetch(`https://graph.microsoft.com/v1.0/users/${uniqueName}/manager`, {
headers: {
authorization: `Bearer ${graphAccessToken}`,
'content-type': 'application/json',
},
});
if (graphResponse.ok) {
const graphResult = await graphResponse.json();
console.log(graphResult)
}
}
}
I want to receive such response
{
"#odata.context": "https://graph.microsoft.com/v1.0/$metadata#directoryObjects/$entity",
"#odata.type": "#microsoft.graph.user",
"id": "1111112-68cf-4896-b2d0-13b5c6264113",
"businessPhones": [
"111 111 11111"
],
"displayName": "Wer, John",
"givenName": "John",
"jobTitle": "SENIOR DEVELOPMENT ARCHITECT",
"mail": "somemail#mail.com",
"mobilePhone": "111 111 1111",
"officeLocation": "Atlanta",
"preferredLanguage": null,
"surname": "John",
"userPrincipalName": "somemail#mail.com"
}
But I get such an error response. What am I doing wrong? Thanks!
{
"error": {
"code": "Authorization_RequestDenied",
"message": "Insufficient privileges to complete the operation.",
"innerError": {
"date": "2022-01-14T20:40:30",
"request-id": "9e2b5937-4bd0-4fdb-a1ae-1b22cef09772",
"client-request-id": "9e2b5937-4bd0-4fdb-a1ae-1b22cef09772"
}
}
}
To get the managers of other users in your organization on your behalf, you need to have User.Read.All delegated permission
Once the permission is assigned, admin consent needs to be granted for the same.
Then you would be able to fetch the managers info of other users in your organization
You can test the same in Graph Explorer first. If it is successful, you can make the changes accordingly in your JavaScript code
Related
I am working with simple HTML and JS code to create a OTP verification form and when user submit the email he will receive an otp and to get verified we need to take id from response.
Here is my response JSON:-
{
"createdBy": null,
"createdAt": "2022-08-20 18:31:14",
"lastModifiedBy": null,
"lastModifiedAt": "2022-08-20 18:31:14",
"id": "huuhby667-4124-41e1-7gt6-t7thgfy7t",
"username": null,
"email": "username#gmail.com",
"phoneNumber": null,
"countryCode": null,
"isEmailVerified": false,
}
Here is my Email Code:-
const emailForm = document.getElementById('email-form');
if(!!emailForm) {
emailForm.addEventListener('submit', function(e) {
e.preventDefault();
const email = document.getElementById('email').value;
const response = fetch('api-email-link', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ email: email }),
}).then(function(response){
return response.json()}).then(function(data){
console.log(data)
document.getElementById('verify-modal-background').style.display = "flex";
}).catch(error => console.error('Error:', error))
});
};
Here is My OTP Verification Code:-
const inputOtp = document.getElementById("otp-input-form");
const id = JSON.parse(response.id);
inputOtp.addEventListener('submit', async function (e) {
e.preventDefault();
let inputs = document.getElementsByClassName("otp-input-box");
let referralCodeInput = document.getElementById("referral-input").value;
let getOtpInput = [];
for (let i=0; i<inputs.length; i++) {
getOtpInput.push(inputs[i].value);
}
const data = {
otp: getOtpInput
};
const response = await fetch(`https://otp-verification/api/auth/${id}/register-email`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' },
body: JSON.stringify(data)
}).catch(e => console.log(e));
I'm trying this but unable to get the ID properly so i can verify this otp for the particular register email.
Whenever a user logins in successfully, this is a sample of the server response:
{
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6ImFjY2VzcyJ9.eyJpYXQiOjE2NDY1MDc5ODEsImV4cCI6MTY0NzExMjc4MSwiYXVkIjoiaHR0cHM6Ly95b3VyZG9tYWluLmNvbSIsImlzcyI6ImZlYXRoZXJzIiwic3ViIjoiMiIsImp0aSI6ImVlMTExOGNhLTVhOGEtNGJiMC1iMDRkLTdlMTUzM2RlMmQ4YyJ9.T5gBB9CYulofSa_rTKP23wNG5YUMyEKtqQIFG0X5RX4",
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6ImFjY2VzcyJ9.eyJ0b2tlblR5cGUiOiJyZWZyZXNoIiwidXNlciI6eyJpZCI6MiwiZmlyc3QiOiJKYW5lIiwibGFzdCI6IkRvZSIsImVtYWlsIjoiaGVsbG8xQGZlYXRoZXJzanMuY29tIiwicGhvbmUiOiIwNzk1ODU3MTM5IiwibG9jYXRpb24iOiJOYWlyb2JpIiwiaXNWZXJpZmllZCI6MCwiaXNBZG1pbiI6MCwicm9sZXMiOiJ1c2VyIiwiY29uZmlybWVkRW1haWwiOjEsImNvbmZpcm1lZFBob25lIjoxLCJjb25maXJtYXRpb25JZCI6IiIsImRlYWN0aXZhdGVkIjowLCJsb2dpbnMiOjAsImJpbyI6IiIsIndlYnNpdGUiOiIiLCJzb2NpYWwiOiIiLCJ1cGxvYWRJZCI6bnVsbCwiY3JlYXRlZEF0IjoiMjAyMi0wMy0wNVQxNzo0NDowNS4wMDBaIiwidXBkYXRlZEF0IjoiMjAyMi0wMy0wNVQxNzo0NDowNS4wMDBaIn0sImlhdCI6MTY0NjUwNzk4MSwiZXhwIjoxNjQ3MTEyNzgxLCJhdWQiOiJodHRwczovL3lvdXJkb21haW4uY29tIiwiaXNzIjoiZmVhdGhlcnMiLCJzdWIiOiIyIiwianRpIjoiNzJjMzZjMWQtZTQwYy00NTE4LTg2NDctYjczNDdiNWFjMzMxIn0.Ba_LBdDBYf5rcTWcR6AaR_uAyqHxpHg3rbqEii8h78I",
"authentication": {
"strategy": "local"
},
"user": {
"id": 2,
"first": "Jane",
"last": "Doe",
"email": "hello1#feathersjs.com",
"isAdmin": 0,
"roles": "user",
"createdAt": "2022-03-05T17:44:05.000Z",
"updatedAt": "2022-03-05T17:44:05.000Z"
}
}
Once the feathersjs accessToken expires, the site hits the api with the refreshToken, and gets a new one without the user's intervention.
I can't however include the refreshToken as there in no way to pass it into callback options of the [...nextauth].js file. How do I go about this?
EDIT: I managed to pass the refresh token, together with the accessToken like so:
// [...nextauth.js]
const providers = [
CredentialsProvider({
name: "Credentials",
authorize: async (credentials) => {
const { email, password, refreshToken = null } = credentials;
try {
if (refreshToken) {
console.log("REFRESHING TOKEN");
const { data } = await axios.post(
API_AUTH,
{
strategy: "local",
action: "refresh",
refresh_token: refreshToken,
},
{
headers: {
accept: "*/*",
"Content-Type": "application/json",
},
}
);
const token = JSON.stringify({
token: data.accessToken,
refresh: data.refreshToken,
});
const user = {
name: data.user.first,
email: data.user.email,
image: "/hkgghlk",
token,
};
if (user) {
return user;
}
} else {
console.log("LOGGING IN");
const { data } = await axios.post(
API_AUTH,
{ strategy: "local", email, password },
{
headers: {
accept: "*/*",
"Content-Type": "application/json",
},
}
);
const token = JSON.stringify({
token: data.accessToken,
refresh: data.refreshToken,
});
const user = {
name: data.user.first,
email: data.user.email,
image: "/hkgghlk",
token,
};
if (user) {
return user;
}
}
} catch (e) {
const errorMessage = e.response.data.message;
throw new Error(errorMessage);
}
},
}),
];
const callbacks = {
async jwt({ token, user, account, profile, isNewUser }) {
if (user) {
const { token: access, refresh } = JSON.parse(user.token);
token.accessToken = access;
token.refreshToken = refresh;
}
return token;
},
async session({ session, token }) {
session.refreshToken = token.refreshToken;
return session;
},
};
Now I know this is a hack. Is there a 'proper' way of doing this? I don't want the refreshToken saved in the session as this is not ideal.
If interested in how feathersjs creates a refresh token, here is how.
I want to delete a user from firebase. And my action is called from a button.
`
export const deleteAccount = () =>{
return async (dispatch, getState) =>{
const token =getState().auth.token;
let response;
try{
response = await fetch('https://identitytoolkit.googleapis.com/v1/accounts:delete?
key=[My_API_key]',
{
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
token:token
})
});
} catch(err){
throw new Error(err.message);
}
if(!response.ok){
const errorResData = await response.json();
console.log(errorResData);
const errorId = errorResData.error.message;
let message = 'Something went Wrong!';
if(errorId === 'INVALID_ID_TOKEN'){
message = 'Please Login Again!!'
} else if(errorId === "USER_NOT_FOUND"){
message = 'User Not Found';
}
throw new Error(message);
}
// dispatch(authentication(resData.localId, resData.idToken, parseInt(resData.expiresIn)*1000 ));
dispatch({type: DELETE});
}
};
`
on consoling my errorResData I am getting response
Object { "error": Object { "code": 400, "errors": Array [ Object { "domain": "global", "message": "MISSING_ID_TOKEN", "reason": "invalid", }, ], "message": "MISSING_ID_TOKEN", }, }
if I console my token I am getting that token.
Thanks in advance!!
I'm not entirely sure why you aren't using the Firebase SDK to do this, but you should be using v3 of the Identity Toolkit API.
await fetch(
"https://www.googleapis.com/identitytoolkit/v3/relyingparty/deleteAccount",
{
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
idToken: FRESH_USER_ID_TOKEN
})
}
);
I am working on a school project with a team of developers. We have created a page where the users have a profile and that profile can be updated. We have come across a bug when a user updates its information. If I update my city for example, then all other information about my user disappears. I have to update the other fields as well, otherwise the database will only store the city that I recently updated.
What I want is that the information I filled in when I created my user is saved, besides from the information I change when I update my user.
Before update: {"username":"bobox","email":"bobox#hotmail.com","password":"test234","gender":"Man","age":"17","city":"Jönköping","games":"Battlefield V","usernameDiscord":"bigbox","usernameSteam":"bigbox","usernameOrigin":"bobox","_id":"wTs8IyRmcA40f3VN"}
After update: {"username":"bobox","email":"bobox#hotmail.com","password":"test234","gender":"","age":"","city":"New York","games":"","usernameDiscord":"","usernameSteam":"","usernameOrigin":"","_id":"wTs8IyRmcA40f3VN"}
Here is the code. I am thankful for all help. If there is anything else you need to know, just let me know.
Updating a user:
script.js
async function updateUser(age, city, gender, games, discord, steam, origin) {
const id = localStorage.getItem("userId")
const response = await fetch('http://localhost:8080/users/' + id, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
age: age,
city: city,
gender: gender,
games: games,
usernameDiscord: discord,
usernameSteam: steam,
usernameOrigin: origin
})
})
console.log(response)
const data = await response.json()
console.log(data)
}
function updateUsersIndex() {
let updateProfileBtn = document.querySelector(".Profile-Right__Update")
console.log(updateProfileBtn)
updateProfileBtn.addEventListener("click", async(event) => {
console.log("hej")
event.preventDefault()
const age = document.querySelector(".Age__Input").value
const city = document.querySelector(".City__Input").value
const gender = document.querySelector(".Gender__Input").value
const discord = document.querySelector(".Discord__Input").value
const steam = document.querySelector(".Steam__Input").value
const origin = document.querySelector(".Origin__Input").value
const games = document.querySelector(".Profile-Right__Select-Game").value
const hidden = document.querySelector(".hidden")
const updateUsers = await updateUser(age, city, gender, games, discord, steam, origin)
})
}
updateUsersIndex()
let profileUpdateBackBtn = document.querySelector(".Profile-Right__Back")
profileUpdateBackBtn.addEventListener("click", async(event) => {
event.preventDefault()
let updateProfile = document.querySelector(".Update-Profile")
let profile = document.querySelector(".Profile__Wrappe")
profile.classList.toggle("Hidden")
updateProfile.classList.toggle("Hidden")
})
app.js:
app.patch('/users/:id', async(req, res) => {
const result = await collectionsNEDB.users.update({ _id: req.params.id }, {
$set: {
"age": req.body.age,
"city": req.body.city,
"gender": req.body.gender,
"games": req.body.games,
"usernameDiscord": req.body.usernameDiscord,
"usernameSteam": req.body.usernameSteam,
"usernameOrigin": req.body.usernameOrigin
}
})
console.log(req.params.id)
res.json(result)
})
Creating a user:
script.js
async function createUser(username, email, password, repeatPassword, games, usernameDiscord, usernameSteam, usernameOrigin) {
const response = await fetch('http://localhost:8080/register', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
username: username,
email: email,
password: password,
repeatPassword,
games: games,
usernameDiscord: usernameDiscord,
usernameSteam: usernameSteam,
usernameOrigin: usernameOrigin
})
})
console.log(response)
const data = await response.json()
if (response.status == 200) {
console.log(data.message)
if (data.message == "SUCCESS") {
console.log("Great")
let Success = document.querySelector(".Success")
Success.innerHTML = "Användare skapad!"
alert("Användare skapad!")
}
} else {
const data = await response.json()
const p = document.querySelector("p")
p.innerHTML = ""
for (let i = 0; i < data.errors.length; i++) {
const error = data.errors[i]
console.log(data.errors)
switch (error) {
case "ERROR_USER_ALREADY_EXISTS":
const hidden = document.querySelector(".Error")
hidden.classList.toggle("Hidden")
hidden.innerHTML = "Användarnamnet existerar redan!"
break;
case "ERROR_EMAIL_ALREADY_EXISTS":
const hiddenEmail = document.querySelector(".Error__Email")
hiddenEmail.classList.toggle("Hidden__Email")
hiddenEmail.innerHTML = "E-mail existerar redan!"
break;
case "ERROR_PASSWORD_MISMATCH":
const hiddenPassword = document.querySelector(".Error__Password")
hiddenPassword.classList.toggle("Hidden__Password")
hiddenPassword.innerHTML = "Lösenordet matchar inte"
break;
}
}
}
}
function init() {
let form = document.querySelector("#Reg-Form-1")
form.addEventListener("submit", async(event) => {
event.preventDefault()
const username = form.querySelector(".username").value
const email = form.querySelector(".email").value
const password = form.querySelector(".password").value
const repeatPassword = form.querySelector(".repeat-password").value
const games = form.querySelector(".gejms").value
const usernameDiscord = form.querySelector(".usernameDiscord").value
const usernameSteam = form.querySelector(".usernameSteam").value
const usernameOrigin = form.querySelector(".usernameOrigin").value
const hidden = document.querySelector(".hidden")
const createUsers = await createUser(username, email, password, repeatPassword, games, usernameDiscord, usernameSteam, usernameOrigin)
})
}
init()
app.js:
app.post("/register", async(req, res) => {
let user, email
if (process.env.NODE_ENV == "development") {
user = await collectionsNEDB.users.find({ username: req.body.username })
email = await collectionsNEDB.users.find({ email: req.body.email })
} else {
dataUser = await Database.collections.users.find({ username: req.body.username })
dataEmail = await Database.collections.users.find({ email: req.body.email })
user = await dataUser.toArray()
email = await dataEmail.toArray()
}
let errors = []
if (req.body.password !== req.body.repeatPassword) {
errors.push("ERROR_PASSWORD_MISMATCH")
} else if (user == false) {
if (email == false) {
let newUser = {
username: req.body.username,
email: req.body.email,
password: req.body.password,
gender: "",
age: "",
city: "",
games: req.body.games,
usernameDiscord: req.body.usernameDiscord,
usernameSteam: req.body.usernameSteam,
usernameOrigin: req.body.usernameOrigin
}
if (process.env.NODE_ENV == "development") {
const result = await collectionsNEDB.users.insert(newUser)
res.status(200).json({ message: "SUCCESS" })
} else {
let db = await Database.connect()
let users = db.collection("users")
const result = await users.insert(newUser)
res.status(200).json({ message: "SUCCESS" })
console.log(result)
}
} else {
errors.push("ERROR_EMAIL_ALREADY_EXISTS")
}
} else {
errors.push("ERROR_USER_ALREADY_EXISTS")
}
if (errors.length > 0) {
res.status(400).json({ errors: errors })
}
})
I try to create auth on my site via battle.net. It's my first experience in OAuth. There is documentation https://develop.battle.net/documentation/api-reference/oauth-api
Now I can get code and want to get access token by code. I provide credentials. Using Koa.js.
const { code } = ctx.query;
const redirect_uri = 'http://127.0.0.1:3000/auth';
const client_id = '0010d...25f44b31...5c34b12f4af7'
const secret = 'MY_VERY_SECRET_CODE';
const scope = 'wow.profile';
if( !code ) ctx.redirect(`https://us.battle.net/oauth/authorize?response_type=code&client_id=${client_id}&redirect_uri=${redirect_uri}&scope=${scope}`);
try {
const { data } = await axios.post('https://us.battle.net/oauth/token', {
grant_type: 'authorization_code',
code,
redirect_uri,
client_id
}, {
auth: {
username: client_id,
password: secret
}
})
console.log(data);
} catch (e) {
console.error(e)
}
ctx.body = {
message: 'OK',
}
Redirect works and I got code. But how I should build a query with the gotten code? But I got error
data:
{ error: 'invalid_request',
error_description: 'Missing grant type' } },
I should use form data type.
formData.append('grant_type', 'authorization_code');
formData.append('code', code);
formData.append('redirect_uri', redirect_uri);
formData.append('client_id', client_id);
const { data: authData } = await axios.post('https://eu.battle.net/oauth/token',
formData,
{
auth: {
username: client_id,
password: secret,
},
headers: {
'Content-Type': `multipart/form-data; boundary=${formData._boundary}`,
}
},
)