Microsoft Graph API

Comments

19 comments

  • Official comment
    Kelly Izer Senior Solutions Consultant
    Awesome Follow-up
    Engaged
    Answer Pro
    Top Contributor
    Celigo University Level 4: Legendary

    Wanted to add some additional content here. I recently did some work with the Graph API and had to create an HTTP connection.

    Here is a video of that process that includes

    1. Setting up the app in the Azure portal to allow Integrator.IO access
    2. Setting up the connection in Integrator.IO to access the Graph API

     

    Additionally, here is a link to screenshots of the setup within integrator if you already have all the needed information from Azure.

  • Kate Larson Senior UX Researcher Community moderator

    Hi Wade Shelton,
    I'd love to get you some guidance on this, but a few more details will help. Which type of connector are you configuring in integrator.io? (For example, we have app connectors for Microsoft Outlook, Microsoft Teams, etc. We also have universal connectors, such as the REST API connector.) Could you also let us know what error(s) you're receiving please?
    Thanks,

    0
  • Wade Shelton
    Engaged

    Kate - 

    I've tried the REST and HTTPs connector.  I don't *think* the application specific connectors (teams, outlook, etc...) would be of much benefit here.

    The Graph API uses bearer token authentication, where the token is retrieved by authenticating against a tenant-specific URL.  Here's an example of what the C# for authenticating looks like, as generated by PostMan:

     

    The API returns the bearer token, as expected, via the JSON body:

     

    In Postman, I can then use that Bearer to authenticate to the Graph API and send a message like so:

    I've tested the above in Postman, and it does successfully trigger an email to all recipients with a plain text file attachment containing "Hello World!"

    What I can't figure out is the following:

    • Which connector type to use?  I've tried both HTTP and REST.  If I use HTTP, I would think I could use OAUTH 2.0 with iClient credentials sent in the body, but I haven't been able to make it work.  Using REST with OAUTH, I haven't found a way to leverage a client ID/Secret key combination for auth.
    • What to use as the base vs login URI on the connection.  This may just be more digging on my part in MS' documentation.

    Either way - just curious if anyone else has tried this yet.  But... I might suggest to Celigo that this could be a really nice feature to enable in-flow notifications...

     

    0
  • Wade Shelton
    Engaged

    Thanks, Kate.  I'm still working with it.  I found an article on a competitor's site showing a Graph integration, so I'm trying to draw parallels to Celigo.

    0
  • Srilekha Tirumala Software Analyst

    Hi Wade Shelton, 

    I can see that you're using Send user's mail operation. 
    Here are a few things you can try: 

    1 . Connecting via Microsoft Outlook Mail connector: 
    In the Microsoft Outlook Mail connector import, we have -  Send user's mail operation under Message resource. We have a hosted OAuth app for Microsoft Outlook Mail and you just need to select the appropriate scopes and Save & Authorize using your Outlook mail account. Once you create a connection, you can create an import with Message resource and select  Send user's mail operation, and provide mappings in the following format: message.attachments[*].[@odata.type] - should be sent in the above format in the Import field mapping to send the data accurately. 

    2. Connecting via generic HTTP adaptor: 
    Additionally, you can also connect via HTTP adaptor, if you want to use your own OAuth app credentials.  To Create an HTTP connection for Microsoft Graph via OAuth 2.0, populate the fields in the following way:  



    Replace tenantId with your Azure tenant ID. And Scopes are delimited with space. 
    Note:  To create a successful connection, integrator IO callback URI(https://integrator.io/connection/oauth2callback) should be added in the corresponding OAuth app.   

    Feel free to reach out in case of any further queries! 

    Thank you! 

    0
  • SWATANTRA ROUT Lead Engineer
    Great Answer

    Hi Wade,

    For Azure, I would recommend to kindly try our Azure Active Directory Connector. 

    https://docs.celigo.com/hc/en-us/articles/360038618172-Set-up-a-connection-to-Azure-Active-Directory

    0
  • Wade Shelton
    Engaged

    Srilekha - 

    The Outlook Mail connector has the same issues as the AAD connector.  It doesn't appear to allow for registered application connections (i.e - OAUTH authentication of an application using a client ID/secret, instead of a username/password).  If it did, I'd love to use it for this purpose.  Interesting that it doesn't, since the base URI in the connector does show that it's using graph.microsoft.com.

    I posted screenshots before, but here are updated ones of the HTTP connector setup.

     

    I have verified that the client ID and secret that I'm using work by using Postman.  One thing to note - the error message I'm receiving says that the method isn't supported.  I'm unable to chose the method/Verb on the HTTP connector (POST, GET, PUT, etc...).  Per MS Documentation (https://docs.microsoft.com/en-us/graph/auth-v2-user) they suggest using POST.  Can you confirm what the HTTP Connector is using?

    0
  • Srilekha Tirumala Software Analyst

    Thanks for the details, Wade Shelton!

    For Microsoft Outlook Mail Connector, we do have a hosted OAuth application in the backend. So that users don't have to worry about creating an OAuth application and maintaining it. Connectors are more user-friendly and I would recommend you to give it a try. 

    Concerning the HTTP connection part, can you please check what you're giving in the How to test this connection sub tab? The ping method should be "GET" just to ping and get your connection working. POST method will be applied from the backend while hitting the "Access Token URL".   

    Let me know if you face any further issues. 
    Thanks!

    0
  • Wade Shelton
    Engaged

    Srilekha -

    That's good to know about the connectors, but how does authentication occur?  Is it user-specific?  In other words, if I set it up under a user account, and that user account is disabled, does my flow stop working?  That's one of the reasons I was pursuing the HTTP route with client ids, so if your OAUTH is somehow negotiating client id creation in the background, I may consider it.

    The tip on the PING method did the trick.  My HTTP connector is now online.  Thanks!

    0
  • Wade Shelton
    Engaged

    Srilekha - 

    I'm not sure if I follow.

    I understand that the backend application is creating a client id and secret, but is that occurring on behalf of the authorizing user?  OAUTH supports the creation of IDs and Secrets to authenticate either a user or an application.  Normally, to authenticate an application, you have to register it, first (which I did in AAD).

    When you ask if Celigo will be able to login or make API calls to the account if the user is disabled, that's why I'm trying to determine whether Outlook connector is creating OAUTH keys for the user, or for the application.  If they're for the user, then I would assume the keys would be invalidated if the user is disabled(?).  If so, then that's a reason to use the HTTP connector with the client id/secret associated with the registered application.

    On the HTTP Connector authentication:  I've enabled debugging on the HTTP connector.  Here is the POST from Celigo:

    Here is the error:

    Here is the same message being sent to the same endpoint using the same ID/secret, but through Postman instead of Celigo.  Here, I get a successful response (202 Accepted) and the email is sent.

     

    0
  • Srilekha Tirumala Software Analyst

    Thanks for the details, Wade Shelton!

    Reg the connector part: We don't create client IDs and secrets for each user login. We have fixed application details. As you said "Normally, to authenticate an application, you have to register it", we have registered the application in the Azure portal in the same way and added the client Id and secret as fixed values in the outlook connector. So, the client Id and the secret will be the same irrespective of the user login. 

    I hope that answers your question.

    Coming to that HTTP Access denied error, are you using any additional scopes in the postman apart from the ones specified in the HTTP connection? It can be due to some missing scope. 

    Either way, If you're still not clear on the above queries, we can set up a call to discuss the same.

    Thank you! 

    0
  • Wade Shelton
    Engaged

    Srilekha - 

    OK.  Thank you for clarifying.  My concern was that, if the authorizing user account were disabled in Azure Active Directory, the connector would no longer function.  If that's not the case, then I can look deeper.

    There are two things that are interesting here, and why I was asking if the connection was specific to the authorizing user:

    • When I use Postman against the Graph API to send the message, I can send from a user account other than my own.  In this case, I'm trying to send from a "Notifications" mailbox, and it works from Postman, where I'm accessing a pre-defined Azure AD application with pre-defined permissions.  It does not work from Celigo, and gives me an access denied error.
    • I'm not declaring any scopes in Postman.  Those are declared on the Azure Active Directory app registration.  I can run this without issues from Postman, but I can't even register the connection from Celigo without declaring the scopes.
    0
  • Srilekha Tirumala Software Analyst

    Hi Wade Shelton, 

    Can you please confirm if you're using this process in your postman? - https://docs.microsoft.com/en-us/graph/auth-v2-service 
    If yes, how are you performing - 3. Get admin consent step?
    If no, could you please link us to the docs which you're following for establishing a connection via postman?

    Also, what is the cookie parameter you're using while fetching the token? 

    We are basically trying to understand the difference between the postman and HTTP connection. 

    Thanks! 

    0
  • Wade Shelton
    Engaged

    Srilekha -

    I'm not explicitly performing the Get Admin Consent step inside of Postman. 

    I've set up an Azure Application Registration similarly to the information here.  You have to be an Admin to do this (and, so, consent is provided).  These aren't the articles I used to actually set this up, but they show the same process.  The app registration in Azure Active Directory serves as a predefined container for permissions/scopes against the selected application (in this case Graph), and using a specified set of credentials (predefined secret/client_id).  

     https://jatindersingh81.medium.com/send-email-using-microsoft-graph-api-using-c-a838d128bb27.  

    https://docs.wpo365.com/article/108-sending-wordpress-emails-using-microsoft-graph

    https://adamtheautomator.com/azure-send-email/#Using_Microsoft_Graph_API_to_Send_Azure_Email

     

    At that point, all that is required is to obtain the bearer token for the request.  I'm doing that in a PostMan pre-request script as follows.  The variables "Auth_URL", "client_secret" and "client_id" are all set up as collection variables.  The rest are set up as environment variables.

     

    // Refresh the OAuth token if necessary
    var tokenDate = new Date(2010,1,1);
    var tokenTimestamp = pm.environment.get("OAuth_Timestamp");
    if(tokenTimestamp){
      tokenDate = Date.parse(tokenTimestamp);
    }
    var expiresInTime = pm.environment.get("ExpiresInTime");
    if(!expiresInTime){
        expiresInTime = 300000; // Set default expiration time to 5 minutes
    }
    if (((new Date() - tokenDate) >= expiresInTime) && (pm.variables.get("OAuth_Token") !== ''))
    {
       pm.sendRequest({
          url:  pm.variables.get("Auth_Url"), 
          method: 'POST',
          header: {
            'Accept': 'application/json',
            'Content-Type': 'application/x-www-form-urlencoded'/*,
            'Authorization': pm.variables.get("Basic_Auth")*/
          },
          body:{
              mode: 'urlencoded',
              urlencoded : [
                {key: 'grant_type', value: 'client_credentials', disabled: false},
                {key: 'resource', value: 'https://graph.microsoft.com', disabled:false},
                {key: 'client_id', value: pm.variables.get("client_id"), disabled:false},
                {key: 'client_secret', value: pm.variables.get("client_secret"), disabled: false}    
              ]  
          }
      }, function (err, res) {
            pm.environment.set("OAuth_Token", res.json().access_token);
            pm.environment.set("OAuth_Timestamp", new Date());
            
            // Set the ExpiresInTime variable to the time given in the response if it exists
            if(res.json().expires_in){
                expiresInTime = res.json().expires_in * 1000;
            }
            pm.environment.set("ExpiresInTime", expiresInTime);
      });
    }

     

    After obtaining the token, I'm just using it in the request:

     

    The actual body of the request is as follows:

    {

      "message": {
        "subject": "Testing API Email Send with attachments From DataFeed",
        "body": {
          "contentType": "Text",
          "content": "Please see attached"
        },
        "toRecipients": [
          {
            "emailAddress": {
              "address": "xxxx.xxxxxxx@rscs.com"
            }
          },
          {
            "emailAddress": {
              "address": "xxxxxx.xxxx@gmail.com"
            }
          }          
        ],
        "replyTo":[{"emailAddress":{"address":"no-reply@rscs.com"}}],
        "attachments":[
            {
                "@odata.type": "#microsoft.graph.fileAttachment",
                "name": "attachment.txt",
                "contentType": "text.plain",
                "contentBytes": "SGVsbG8gV29ybGQh"
            }
        ]
      },
      "saveToSentItems": "false"
    }
    0
  • Srilekha Tirumala Software Analyst

    Hi Wade Shelton, 

    Thanks for the details! 
    From the link that you've provided(https://adamtheautomator.com/azure-send-email/#Using_Microsoft_Graph_API_to_Send_Azure_Email), I tried out one connection config. Can you please try out the below connection and test your flow?
    Also, from one of the links I can see one scope parameter added (scope = "https://graph.microsoft.com/.default"), while fetching the access token. Are you using that in your postman configuration? 

    Here's one connection configuration as per the above link,




    Let us know if you're able to integrate with this connection configuration.

    Thanks for patiently working with us! 

    0
  • Wade Shelton
    Engaged

    Srilekha  

    Apologies, but I had some issues that I had to work on last week.

    I did try to set this up in .io, but as of yet, have not had a successful connection.  I'm still working on troubleshooting, but will try to post screenshots later.

    0
  • Anuj kumar Maurya
    Engaged
    Celigo University Level 4: Legendary
     
    Srilekha Tirumala thanks for that solutions for MS Graph Connections but when Access token expired in Oauth2.0 then how to exactly manage i've tried but not successful.
    Please share the ss for expired token in Oauth2.0 for MS Graph API as well.
    0
  • Srilekha Tirumala Software Analyst

    Hi Anuj kumar Maurya

    Are you using the same configuration as above? (i.e - Grant type - client_credentials)

    Most of the time for OAuth 2.0 connections, the refresh mechanism is handled under the hood. We might need some further details to debug why it is failing. Please do share the connections details by hiding the sensitive info. 

    Thank you! 

    0
  • Tyler Lamparter Principal Product Manager
    Awesome Follow-up
    Engaged
    Top Contributor
    Answer Pro
    Celigo University Level 4: Legendary

    Wade Shelton I have a graph api connection working and here is my config. The marked out part of the url is your tenant id. You may need to provide additional scopes, but I used the app default and set offline_access. The offline_access scope I believe has to be there so we get refresh tokens.

    0

Please sign in to leave a comment.