0
votes

I am using azure functions to serve as a secure api between my front end application and MS Graph.

I have a B2C AD for which I am able to get a single user and list all users, using my azure function.

I get 401 unauthorised when I try to create a user.

My API app is registered in B2C with permissions Directory.Read.All, Directory.ReadWrite.All, Application.ReadWrite.All, AuditLog.Read.All and User.ReadWrite.All - all of them indicate they have admin consent.

Client secret is in order and is used as part of the token request.

I get the access token from the https://login.microsoftonline.com/{tenant id}/oauth2/v2.0/token end point. This is how I obtain the token:

const APP_ID = 'XXXXXXX';
const APP_SECERET = 'XXXXXXXX';
const TOKEN_ENDPOINT ='https://login.microsoftonline.com/{tenant id}/oauth2/v2.0/token';
const MS_GRAPH_SCOPE = 'https://graph.microsoft.com/.default';
const MS_GRAPH_USER = "https://graph.microsoft.com/v1.0/users"

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'
};

let token = null

await axios
.post(TOKEN_ENDPOINT, qs.stringify(postData))
.then(async (response) =>  {

    token = response.data.access_token}) etc etc etc...

Error response is simply a 401 Unauthorised. I can post the full message if required.

Where am I going wrong?

Thanks

enter image description here

Error response looks like this:

 response: {
status: 401,
statusText: 'Unauthorized',
headers: {
  'cache-control': 'private',
  'content-type': 'application/json',
  'request-id': '93918a37-f0ed-44c9-85ad-d22157e88239',
  'client-request-id': '93918a37-f0ed-44c9-85ad-d22157e88239',
  'x-ms-ags-diagnostic': '{"ServerInfo":{"DataCenter":"UK South","Slice":"SliceC","Ring":"4","ScaleUnit":"002","RoleInstance":"AGSFE_IN_40"}}',
  'www-authenticate': 'Bearer realm="", authorization_uri="https://login.microsoftonline.com/common/oauth2/authorize", client_id="00000003-0000-0000-c000-000000000000"',
  'strict-transport-security': 'max-age=31536000',
  date: 'Tue, 15 Dec 2020 15:20:10 GMT',
  connection: 'close',
  'content-length': '302'
},
config: {
  url: 'https://graph.microsoft.com/v1.0/users',
  method: 'post',
  data: 'accountEnabled=true&mailNickname=TT&passwordProfile%5BforceChangePasswordNextSignIn%5D=true&passwordProfile%5Bpassword%5D=XXX',
  headers: [Object],
  transformRequest: [Array],
  transformResponse: [Array],
  timeout: 0,
  adapter: [Function: httpAdapter],
  xsrfCookieName: 'XSRF-TOKEN',
  xsrfHeaderName: 'X-XSRF-TOKEN',
  maxContentLength: -1,
  maxBodyLength: -1,
  validateStatus: [Function: validateStatus],
  'content-type': 'application/json',
  Authorization: 'Bearer XXX (removed)'
},
request: ClientRequest {
  _events: [Object: null prototype],
  _eventsCount: 7,
  _maxListeners: undefined,
  outputData: [],
  outputSize: 0,
  writable: true,
  _last: true,
  chunkedEncoding: false,
  shouldKeepAlive: false,
  useChunkedEncodingByDefault: true,
  sendDate: false,
  _removedConnection: false,
  _removedContLen: false,
  _removedTE: false,
  _contentLength: null,
  _hasBody: true,
  _trailer: '',
  finished: true,
  _headerSent: true,
  socket: [TLSSocket],
  connection: [TLSSocket],
  _header: 'POST /v1.0/users HTTP/1.1\r\n' +
    'Accept: application/json, text/plain, */*\r\n' +
    'Content-Type: application/x-www-form-urlencoded\r\n' +
    'User-Agent: axios/0.21.0\r\n' +
    'Content-Length: 127\r\n' +
    'Host: graph.microsoft.com\r\n' +
    'Connection: close\r\n' +
    '\r\n',
  _onPendingData: [Function: noopPendingOutput],
  agent: [Agent],
  socketPath: undefined,
  method: 'POST',
  insecureHTTPParser: undefined,
  path: '/v1.0/users',
  _ended: true,
  res: [IncomingMessage],
  aborted: false,
  timeoutCb: null,
  upgradeOrConnect: false,
  parser: null,
  maxHeadersCount: null,
  reusedSocket: false,
  _redirectable: [Writable],
  [Symbol(kCapture)]: false,
  [Symbol(kNeedDrain)]: false,
  [Symbol(corked)]: 0,
  [Symbol(kOutHeaders)]: [Object: null prototype]
},
data: { error: [Object] }

}, isAxiosError: true, toJSON: [Function: toJSON] }

EDIT:

Tried graph explorer and despite having consent for each of the permissions I get a 403 forbidden

enter image description here

I've asked my global admin to confirm but I think I have the application administrator role.

Also, as my registered app has granted admin permissions I thought this would have worked as it does not rely on my permissions...?

Thanks

1
can you please provide the correlation id and timestamp of error message - Sruthi J
@SruthiJ-MSFTIdentity I have added an error response to the body. Couldn't explicitly see the attributes your requested - JTInfinite
Let us know which role you have and also can you please try this using graph explorer and share the error details if you are facing any issue( correlation id and timestamp) - Sruthi J
Thanks @SruthiJ-MSFTIdentity - I have added details of the graph explorer feedback as well as some comments. Look forward to hearing from you - JTInfinite
can you please provide request-id and timestamp in the text format - Sruthi J

1 Answers

1
votes

Please use the below code for getting the user list and Create a new user

 const request = require('request');
    let tokentest='';
    const endpoint = "https://login.microsoftonline.com/tenantid/oauth2/v2.0/token";
    const requestParams = {
        grant_type: "client_credentials",
        client_id : "clientid",
        client_secret : "secret",
        scope: "https://graph.microsoft.com/.default"
    };
     user = {
      accountEnabled: true,
      displayName: "Adele Vance",
      mailNickname: "AdeleV",
      userPrincipalName: "AdeleghhhVgghhh@xxx",
      "passwordProfile" : {
        forceChangePasswordNextSignIn: true,
        password: "xWwvJ]6NMw+bWH-d"
      }
    };
        
    
    request.post({ url:endpoint, form: requestParams }, function (err, response, body) {
        if (err) {
            console.log("error");
        }
        else {
            console.log("Body=" + body);
            let parsedBody = JSON.parse(body);         
            if (parsedBody.error_description) {
                console.log("Error=" + parsedBody.error_description);
            }
            else {
                console.log("Access Token=" + parsedBody.access_token);
    
               createGraphAPI(parsedBody.access_token);
                testGraphAPI(parsedBody.access_token)
            }
        }
    });
    
    function testGraphAPI(accessToken) {
        request.get({
            url:"https://graph.microsoft.com/v1.0/users",
            headers: {
              "Authorization": "Bearer " + accessToken
            }
            
        }, function(err, response, body) {
            console.log(body);
        });
        
    }
    
    
    function createGraphAPI(accessToken) {
      request.post({
          url:"https://graph.microsoft.com/v1.0/users",
          headers: {
            "Authorization": "Bearer " + accessToken,
            'content-type': 'application/json'
           
          },json:user
        
    
          }, function(err, response, body) {
            console.log(body);
        });
        
    }