San Jay Falcon
San Jay Falcon

Reputation: 1013

MS Graph API (mail) issue with POST and scopes

Trying to get this to work and GET / Patch work just fine, but POST gives me HTTP STATUS 400 and 403. Must be something with scopes. In Azure AD I have set the following scopes:

Mail.ReadWrite (Delegated)
Mail.ReadWrite (Application)
Mail.Send Delegated)
Mail.Send (Application)

So, signing in works just fine, getting / patching messages as well. Only POST doesnt seem to work. See code for exact error messages.

Angular10

App.module

export function MSALInstanceFactory(): IPublicClientApplication {
      return new PublicClientApplication({
        auth: {
          clientId: 'xxxx',
          authority: 'https://login.microsoftonline.com/common/',
          redirectUri: '/',
          postLogoutRedirectUri: '/#/login'
        },
        cache: {
          cacheLocation: BrowserCacheLocation.LocalStorage,
          storeAuthStateInCookie: isIE, // set to true for IE 11
        },
        system: {
          loggerOptions: {
            loggerCallback,
            logLevel: LogLevel.Info,
            piiLoggingEnabled: false
          }
        }
      });
    }

    export function MSALInterceptorConfigFactory(): MsalInterceptorConfiguration {
      const protectedResourceMap = new Map<string, Array<string>>();
      protectedResourceMap.set('https://graph.microsoft.com/v1.0/me', ['user.read', 'mail.readWrite', 'email']);
      // also tried these scopes .. 
      // protectedResourceMap.set('https://graph.microsoft.com/v1.0', ['user.read', 'mail.readWrite', 'email']);
      // protectedResourceMap.set('https://graph.microsoft.com/v1.0/query', ['user.read', 'mail.readWrite', 'email']);
      // protectedResourceMap.set('https://graph.microsoft.com/v1.0/search/query', ['user.read', 'mail.readWrite', 'email']);

      return {
        interactionType: InteractionType.Redirect,
        protectedResourceMap
      };
    }

    export function MSALGuardConfigFactory(): MsalGuardConfiguration {
      return { interactionType: InteractionType.Redirect };
    }

@NgModule({
    imports: [
      BrowserModule,
      // etc..
    ],
    declarations: [AppComponent],
    providers: [
      NgEventBus,
      ChhServices,
      SynclogService,
      AppService,
      AuthService,
      GapiServices,
      {
        provide: ErrorHandler,
        useClass: ErrorService,
      },
      {
        provide: HTTP_INTERCEPTORS,
        useClass: MsalInterceptor,
        multi: true
      },
      {
        provide: MSAL_INSTANCE,
        useFactory: MSALInstanceFactory
      },
      {
        provide: MSAL_GUARD_CONFIG,
        useFactory: MSALGuardConfigFactory
      },
      {
        provide: MSAL_INTERCEPTOR_CONFIG,
        useFactory: MSALInterceptorConfigFactory
      },
      MsalService,
      MsalGuard,
      MsalBroadcastService
    ],
    bootstrap: [AppComponent],
  })
  export class AppModule { }

Auth.service

signIn() {
    console.log('AuthService::signIn');
    this.msalService.loginPopup().subscribe((result) => {
        this.accessToken = result['accessToken'];
        console.log('authority', result, this.accessToken);
    });
}

testGraphApi() {

    // 200 OK
    const apiGet = this.httpClient.get(`https://graph.microsoft.com/v1.0/me/messages/`).subscribe((data) => {
        console.log('get', '/me/messages', data);
    });

    const categories: any[] = ['custom'];
    const body = {
        subject: '2320, with tags',
        flag: { flagStatus: 'flagged' }, // notFlagged
        categories,
        body: {
            contentType: 'html',
            content: 'lalala'
        },
        inferenceClassification: 'other'
    };

    const id = 'AQMkADAwATM3ZmYAZS0zOTkANy02MTAwAC0wMAItMDAKAEYAAAM_TfJTK-tISYhjZdaCkkbgBwCPpkVcscQ9QJF-EDzB8h_oAAACAQwAAACPpkVcscQ9QJF-EDzB8h_oAAACHbIAAAA=';

    // 200 OK
    const apiPatch = this.httpClient.patch(`https://graph.microsoft.com/v1.0/me/messages/${id}`, body).subscribe((data) => {
        console.log('patch', '/me/messages', data);
    });

    const bodySendMail = {
        'message': {
            'subject': 'Meet for lunch?',
            'body': {
                'contentType': 'Text',
                'content': 'The new cafeteria is open.'
            },
            // etc..
        }
    }

    const headers = new HttpHeaders({ 'Content-Type': 'application/json', 'Authorization': `Bearer ${this.accessToken}` });

    // 403 Forbidden
    // "code": "ErrorAccessDenied",
    // "message": "Access is denied. Check credentials and try again.",
    const apiSendMail = this.httpClient.post(`https://graph.microsoft.com/v1.0/me/sendMail`, bodySendMail, { headers }).subscribe((data) => {
        console.log('post', '/me/sendMail', data);
    });

    const bodySearch = {
        'requests': [
            {
                'entityTypes': [
                    'message'
                ],
                'query': {
                    'queryString': 'ref:6019d6bf1ce3425fb833559e'
                },
                'from': 0,
                'size': 5
            }
        ]
    }

    // 400 Bad Request
    // "code": "AuthenticationError",
    // "message": "Error authenticating with resource",
    const apiSearch = this.httpClient.post(`https://graph.microsoft.com/v1.0/search/query`, bodySearch, { headers }).subscribe((data) => {
        console.log('post', '/search/query', data);
    });
}

Upvotes: 0

Views: 807

Answers (1)

unknown
unknown

Reputation: 7483

// 403 Forbidden
// "code": "ErrorAccessDenied",
// "message": "Access is denied. Check credentials and try again."

Send mail API needs Mail.Send permission. When requesting /me endpoint which bases the current signed-in user, it should have the delegated permission.

So you need to add Mail.Send of delegated permission in the portal and add it in your code.

// 400 Bad Request
// "code": "AuthenticationError",
// "message": "Error authenticating with resource"

searchEntity: query API needs the Mail.ReadWrite delegated permission. This api only supports "work or school account". A work account typically uses an organization’s custom domain name or company name, such as "[email protected]" or "[email protected]".

enter image description here

You could test to request the api in Graph Explorer.

Upvotes: 1

Related Questions