Skip to main content

MS Graph API

Comments

33 comments

  • Kate Larson Community moderator Principal Technical Writer
    Celigo University Level 3: Master

    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

    Kate - 

    As a follow-up... here's a little more of what I'm seeing.

    I have created an app registration in Azure for Celigo and created a client id/secret key.

    Inside of Celigo, I'm trying to set up a connection as follows:

     

     

    All other fields have been left to their defaults.  I have tried using a grant type of both "Client Credentials" and "Authorization code", but have, as of yet, been able to successfully connect.  Whenever I try, I consistently get the following:

     

     

    0
  • Kate Larson Community moderator Principal Technical Writer
    Celigo University Level 3: Master

    Thanks for providing these details, Wade Shelton. I'm checking with some folks internally on any recommendations they have, but encourage others reading to share their experience integrating with the Graph API please. I also shared your suggestion regarding in-flow notifications in our enhancement requests forum.

    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
  • Wade Shelton
    Engaged

    Srilekha - 

    Thank you for that.  I was able to find a few things that needed to be adjusted on the HTTP connector and can at least get to the point where I try to authenticate.  I'm now getting this error after authorizing the connection with Azure AD, though, and was curious if you can offer any further advice:

    "Sorry, but we were not able to successfully authenticate your connection.
    {"source":"application","code":405,"message":"{\r\n \"error\": {\r\n \"code\": \"UnknownError\",\r\n \"message\": \"Method not allowed\",\r\n \"innerError\": {\r\n \"date\": \"2021-04-14T15:52:25\",\r\n \"request-id\": \"7395e435-0201-4262-91eb-57d3d076b9dc\",\r\n \"client-request-id\": \"7395e435-0201-4262-91eb-57d3d076b9dc\"\r\n }\r\n }\r\n}","resolved":false,"occurredAt":1618415545083}"

    0
  • Srilekha Tirumala Software Analyst

    Hi Wade Shelton, 
    Are you getting this error right after you "Save and Authorize" or after the scopes page?
    Can you please share the details of your connection? so that we can try and reproduce the issue from our end.

    Thank you! 

    0
  • Wade Shelton
    Engaged

    Srilekha -

    I am getting this after I attempt to Save & Authorize.  Screenshots below.

    I'm not sure what you're looking for re: connection details.  Are you asking for the client_id, secret_key and tenant ID?  If so, that's not something I can share, but I can share my screen for troubleshooting.

     

     

     

    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

    Swatrantra - 

    Looking at the AAD Connector, I don't see scopes that provide for Mail.Send.  It also appears that the AAD connector only supports authentication via a named user.  One of the benefits of the HTTP connector is the use of client ids/secrets to authenticate as a registered application (through OAUTH) instead of as a user.  That mitigates user-related issues (Expanding mail privileges for a named user, password changes, terminations, etc...)

    Is there some way of using the Mail.Send and Client IDs/Secrets with the AAD connector?

    0
  • Srilekha Tirumala Software Analyst

    Hi Wade Shelton, 

    Mail-related scopes are available under Microsoft Outlook Mail connector, please try that as suggested above. But, If you are trying to use your own OAuth credentials (client ID and secret), the best option is to use HTTP. 
    Regarding the error, can you please send out the connection configuration screenshots? You can hide the sensitive info(client id, secret, and tenant ID). Because it is hard to guess the issue from the error. We need to check further. 

    Thank you! 

    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

    Well... celebrated too early.

    The connector is online, but HTTP calls to the same call endpoints as I'm using in Postman are failing.

    Can you provide information re: how oauth is managed on your mail connector?

    0
  • Srilekha Tirumala Software Analyst

    Hi Wade Shelton, 

    I am not sure if I completely comprehend your question about the user account being disabled. Are you talking about the Outlook mail user account?
    Basically, we have the OAuth application credentials(client id and client secret) stored in the backend and it works the same way as your OAuth application. We don't dynamically create an application for every user but there's one static public app that is used to authenticate your connection. 

    Reg HTTP import: can you please send us the error details? We will try to look into it further. (debugs/screenshots would help). 

    Thank you! 

    0
  • Wade Shelton
    Engaged

    Srilekha - 

    Yes.  It's not immediately clear from your Outlook connector whether OAUTH client ID/secret are being generated, and if they are, whether they are specific to the user account used to authorize the connection.  After all, these are enterprise integrations, so it would be desirable for them to survive longer than any single user account (in the case of user termination).  Since O365 requires that service accounts (not assigned to a physical account) be licensed, tying credentialing to a single user isn't ideal, anyway.

    On the other hand, since OAUTH allows for authentication of an application separately from a user account, leveraging a registered application via an assigned client ID and secret allows the application to function without regard to a specific named user.  That's the route I was trying to leverage by exposing an AAD registered application with an assigned id and secret with declared permissions on the Graph API.

    I'll turn on the debugger and see if I can capture any results.  If so, I'll post them here.  

     

    0
  • Srilekha Tirumala Software Analyst

    Hi Wade,

    To answer your question: The Client ID and Secret of the backend application are not user-specific(not generated dynamically) and they are static and perpetual. But, one question here: if the user account disabled, will we be able to login/make API calls to that account? 
    While authenticating via postman/HTTP, we need to log in to one outlook mail account, grant permissions, and fetch the code, and then the access token. It is the same via connector as well. 


    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, 

    I think we are diverging on the OAuth app part.
    Please let us know if it is fine to set up a call to be on the same page. 

    Thanks! 

    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
  • Srilekha Tirumala Software Analyst

    Sure, Wade! 

    Once you look into it, let us know if we can help. 

    Thanks! 

    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

Please sign in to leave a comment.