In just under two weeks I’ll have to present how to use OAuth 2.0 authentication to call REST APIs of Dynamics 365 Business Central. Should be easy. Not only I have already done OAuth integrations , but there is also a nice step-by-step tutorial by Microsoft specifically done for Business Central. So, I followed the steps to the letter (as much as that was possible), and after all was done, I tried to use Postman to get myself an OAuth 2.0 token for invoking Business Central REST APIs, but it didn’t work. No matter what I did, Postman kept returning this: (Could not complete OAuth 2.0 login. Check Postman Console for more details.) So I checked the Postman Console for more details. (access_denied; Error) Quite some detail. After a ridiculous amount of time troubleshooting this, I figured it out. Depending on how your Business Central trial account was configured you may encounter this problem. On top of it add the fact that the documentation isn’t exactly straightforward and at couple of places leaves you (educated-)guessing. So I decided to write this blog in case you (or myself at some future point after I will have forgotten I’ve been in this mess) ever need it. For the sake of simplicity, I’ll just assume that you have a Business Central account, trial or otherwise. Let’s start first with how to really set it OAuth 2.0 authentication without any need for guesswork. 1. Sign in to Azure Portal with the account you use to sign in to Business Central. 2. Create an Azure Active Directory Web app / API registration With OAuth 2.0 authentication things are not simple, for a reason. You have a back-end AAD-managed resource you want to access (such as Business Central) and a third-party app that wants to access it (whatever integration you are developing). There should be a contract between the two, that applies only to those two parties, that controls whether an app can access your AAD-managed resource. That’s why you need to create an app registration record in your Azure Active Directory to control access the integration you are developing has to Business Central. This is what you are configuring in this stage. In the navigation pane, click on Azure Active Directory If, by any chance, you don’t see this there, then click on All Services : Then in the All Services search box, enter “Directory”: And then in the list of found entries click Azure Active Directory . Follow these steps to create an app registration: In the list of the Azure Active Directory resources, click App registrations . Click New application registration : Populate the Create blade with your app information: Name should be unique for your Active Directory. Application type must be Web app / API. Sign-on URL must be https://businesscentral.dynamics.com/ Here’s an example: Click Create . After a few seconds the Registered app blade will show up automatically and display the information about your freshly created app registration. In the Registered app blade, select and copy the value under Application ID , or alternatively hover your mouse over it and click the copy button that appears: . Store this value somewhere; you will use it as the Client ID during OAuth 2.0 authentication protocol. Microsoft’s Getting Started article fails here. First, it directs you to a generic Azure how-to document which explains how to create any application registration type, including native (which you must not choose for Business Central OAuth 2.0 authentication). Second, it never tells you which Sign-on URL to use. It should be obvious, but you might get creative with known URLs like https://login.microsoftonline.com/ or whatever else. Now that you created your app registration, you must configure it. In your Registered app blade, click Settings : In the Settings blade, under API Access section, click Required permissions : In the Required permissions blade, click Add : In the Add API access blade, click 1 Select an API : In the Select an API blade, you need to select Dynamics 365 Business Central , but most likely it is not listed. Don’t worry, you can still search for it. In the search box, enter “Dynamics”, and then click Dynamics 365 Business Central: Click Select . In the Enable access blade, click the Delegated permissions checkbox. Click Select . In the Add API access blade, click Done . In a few seconds, a notification message will confirm successful configuration of permissions: Back in the Settings blade (should be still visible), still under API Access section, click Keys : In the Keys blade, under Passwords section, populate the first empty row by entering a unique value into the Key description text box, and selecting one of the available durations from the Duration combo box: Your key description should be descriptive enough to indicate which app (or integration) it is being used for. Don’t use generic names as I did here if you are developing a lot of different integrations. Click Save : This generates your access key: A warning message on top tells you to copy the key value. It will only be visible once, and once you navigate away from the Keys blade, you won’t be able to retrieve the key, and you would have to create a new one. Copying this key is important. Copy it and store it somewhere. Don’t lose it. This key will be used as your client secret when authenticating using OAuth 2.0, and you should only ever use one key for one integration (one application) that communicates with the back end. You can easily revoke the keys or create as many keys as you need for other integrations (applications) you will develop. In case you prefer it this way, here’s a short gif video that shows all of these steps in one go: Before you can try out your OAuth 2.0 authentication, you need to copy your directory ID. It will be used during the authentication protocol, and Azure will use it to know which specific Azure Active Directory to look into. Close all the open blades, or simply click Azure Active Directory to return back to the overview of your active directory. In the list of resources, click Properties: In the list of properties, locate the Directory ID property, and select and copy its value. Alternatively, click the copy button . 3. Test your OAuth 2.0 with Postman I am using Postman for two reasons. First, apparently it’s the new black and these days everyone and his sister is using it to try out REST APIs. The second reason is that it already comes bundled with full support for OAuth 2.0 authentication and I don’t need to develop my own client. Follow these steps: Start Postman. If you didn’t do it already, then download and install Postman from https://www.getpostman.com/ , and then start it. Close the Create New dialog. You don’t have to, here you really can do nearly any of the offered options, but since I want to show only how to get the OAuth 2.0 authentication token, this is the simplest options. In the Untitled Request tab, click Authorization . From the Type combo box, select OAuth 2.0: Click Get New Access Token : This will show the Get New Access Token dialog. Enter any descriptive name in the Token Name field. This is completely irrelevant. Leave Grant Type at Authorization Code default value. In the Callback URL field, enter https://businesscentral.dynamics.com/ In the Auth URL field, enter the specific authorization URL for your Azure Active Directory. If you don’t have it, it’s this: https://login.windows.net/ /oauth2/authorize?resource=https://api.businesscentral.dynamics.com If your Directory ID (you copied it in the previous step, remember?) is eec4d82e-660b-4afa-b4c8-c8b60d5fee4c, your Auth URL will look like this: https://login.windows.net/eec4d82e-660b-4afa-b4c8-c8b60d5fee4c/oauth2/authorize?resource=https://api.businesscentral.dynamics.com In the Access Token URL field, enter the token URL for your AAD. It’s similar to the one above, only instead of the “authorize” part, it has “token”. Something like this: https://login.windows.net/eec4d82e-660b-4afa-b4c8-c8b60d5fee4c/oauth2/token?resource=https://api.businesscentral.dynamics.com Important: For these two endpoints you must use the ones as explained in this and the previous step. Do not use the endpoints listed under the Endpoints section of your Azure Active Directory App registrations blade, that you may be familiar with from earlier. Those endpoints only accept POST requests, and Postman makes GET requests during OAuth 2.0 authorization process. In the Client ID field, enter your app registration ID (you copied it earlier, right after creating it). In the Client Secret field, enter the key value from your API Access Keys configuration of your app (you also copied it earlier). This is what your fully configured Get New Access Token dialog may look like at this point: Click Request Token . This is where OAuth 2.0 protocol kicks in. Postman will open a dialog containing an embedded browser and send a HTTP GET request to your authentication URL and pass the necessary parameters (Client ID is the most important at this stage). Enter your credentials. Don’t worry, Postman will not see them. At this point, even if you entered correct credentials, there are several possible outcomes: If you provided wrong Client ID or Callback URL different than the one specified during the App registration creation process: This is easy, simply check all the details of the error message (always provided!), they will tell you exactly what’s wrong, and it should be easy to fix. If you provided an incorrect client secret, you will get this: If the incorrect client secret is the reason why you see this message, it’s also easy. Go back, provide the correct client secret, and retry. If you got the client secret correctly, option d) will apply to you. However, there may be that the option c) applies to you. If your Azure Active Directory is not a managed AAD and doesn’t have an administrator, then you will also see this: You, lucky you, you! You are really lucky to have me, because you don’t have to go through the troubles I went through, that made me spend two hours writing this post for you. There is more info for you a little further down. If you entered all OAuth 2.0 details correctly and your AAD is managed, then you get this: Now, if you got this last one, under d), check the Consent on behalf of your organization , then click Accept , back in Postman in the Manage Access Tokens dialog scroll down, then click Use Token , and see you next time, we are done here, really – you just got your OAuth 2.0 token and can play around your Business Central APIs using production-grade security. However, however… if you were as unlucky as I was the first time, you got this guy: It took me ridiculous amounts of time to troubleshoot this one. No piece of documentation, no errors to hang on and google a stackoverflow solution, no absolutely nothing. Total darkness. It actually took me two additional Business Central trial tenants before I got one working. I got surprised when it finally worked, and then I figured out what is the problem: apparently you cannot use OAuth with an unmanaged Azure Active Directory. To check if your AAD is managed, click All Services, then search for “Subscriptions” and then you see no subscriptions listed, like this: Click Add and then attempt to add a subscription. If your AAD is unmanaged, you won’t be able to do this. But how did I get into this mess in the first place? I must have done something wrong! Er, no. What I did is that I simply subscribed for Business Central trial with my e-mail address with an account that didn’t have AAD tied to it already. And this will happen to you too, if you do the same. I verified this by getting myself two extra domains (cost me $3.34 at NameCheap.com) that I didn’t first sign up for Azure, and then successfully signed up for Business Central trial only to get stuck at the OAuth 2.0 wall. What happens when you sign up for Business Central trial? One of the following may happen: If you use an e-mail with a domain that already has a production Business Central tenant, you will not be able to sign up for a new trial. If you use an e-mail with a domain that already has a trial Business Central tenant, you will be joined into that trial organization (after successful verification that you own that e-mail) If you use an e-mail with a domain that already has a managed Azure AAD (for example, from Office 365) but no Business Central trial tenant, your new Business Central tenant will be provisioned, and you’ll be able to use OAuth 2.0 using the steps I described in this blog. If you use an e-mail with a domain not associated to an active Azure AAD, a new shadow Azure Active Directory (unmanaged AAD) will be created for you first, and then a new Business Central tenant will be provisioned. You won’t be able to use OAuth 2.0 until you perform the administrative takeover . Luckily, Azure provides a guide how to perform the administrative takeover: https://docs.microsoft.com/en-us/azure/active-directory/users-groups-roles/domains-admin-takeover The kind of takeover you want to perform is the internal takeover, and the steps are explained here: https://docs.microsoft.com/en-us/azure/active-directory/users-groups-roles/domains-admin-takeover#internal-admin-takeover Simply follow these steps, and your AAD becomes a managed one, and you are now able to authenticate with OAuth 2.0. Now, I don’t know (but I do intend to find out!) whether this is something by design, or simply a bug somewhere in either the sign-up process or OAuth 2.0 process. I have strong reasons to suspect that it’s actually a bug. It can be 100% repeated if you try creating your new Business Central trial from an e-mail that has no prior knowledge or ties to any AAD domain. If you sign up using such an e-mail, even though Business Central wires up your fresh new AAD, it doesn’t allow you to use OAuth. However, if you have AAD already, and then sign up for Business Central, it seems to work. To me, this sounds like a bug, especially because setting up AAD is an infrastructure task, and signing up for Business Central trial is intended to be performed by people without any knowledge of AAD or infrastructure or anything. In the course of finding out what exactly is causing OAuth 2.0 to fail and then finding out what fixes it, I have created a crazy number of Azure Active Directories and demo Business Central tenants, and what confuses me most is that I even managed to figure out a way to create an unmanaged AAD, get Business Central on top of it, and then still be able to use OAuth 2.0 without performing administrative takeover (I don’t have more time to play around this specific scenario, but it seems to me that if you create a new AAD from the context of an existing Azure account, and then create a user for that AAD, and then sign up for Business Central, you get an unmanaged AAD and working Business Central OAuth 2.0. Seems that the only way to get a “messy” one is to start the entire process from the Business Central trial sign-up page and use an account not bound to an AAD already. In any case, I hope this helped you, and now I am tired, but there are miles to go before I sleep. Read this post at its original location at http://vjeko.com/how-do-i-really-set-up-azure-active-directory-based-authentication-for-business-central-apis/ , or visit the original blog at http://vjeko.com . 5e33c5f6cb90c441bd1f23d5b9eeca34 The post How do I: Really set up Azure Active Directory based authentication for Business Central APIs appeared first on Vjeko.com .
↧
Blog Post: How do I: Really set up Azure Active Directory based authentication for Business Central APIs
↧
Forum Post: Page - Field property set to FALSE but still showing by default
Dear Community, What I try to achieve: I want to customize the page/columns visibility so that by default the page will show the most relevant columns; and hide the ones less frequentely used (but user can decide to add them via personalization options) To achieve that: I went to the page design and changed the VISIBLE property to TRUE to the fields/columns I want to show by default; and set it to FALSE for the ones I do not want to show by default but could be added by users manually. My problem: Even though I have set the property VISIBLE to FALSE these fields/columns are still showing. To be noted: I have deleted all the user pernalizations to make sure there is no conflict in my testing; I have also restarted the client & even the NAV instance without success to resolve; I also checked that in the page there is no code creating an inconsistent behavior with what I'm trying to do. I have been trying to achieve that with the Warehouse Receipt Page; more particulalrly on its subform containing the warehouse receipt lines (respectively page ID 5768 / 5769) Thanks for your help !
↧
↧
Forum Post: Page List - Add totals to a list from a header table
Dear Community, I would like your advice how to best handle the below use case. What I try to achieve: In a list page feeds from a header kind of table (for example, Warehouse Receipt Header); for each line (1 header) I want to add totals which will be sums or calculation from fields at the line level. For example, the page Warehouse Receipts is the list of Warehouse Headers; in that page I would like to add fields/columns with the total base quantities, total quantity to receipt, total quantity oustanding, etc. To be noted: I really want to show these totals within the list; using a pagepart will not fulfil my use case. Would you please recommend what is the standard ways / most recommended ways to achieve that ? The fact that we cannot querry the database directly makes it a little counter intuitive at first, so I'm at a loss to understand how to best manage that case. Thanks for your help and support, Regards
↧
Forum Post: RE: Facing some transactions in inventory interim account in navision
Dear Mehan, I found this to identify the direct posting entries on GL Filter on the Source Code field with ‘<>INVTPCOST‘. Hope it will be helpful
↧
Forum Post: Deleting General Ledger Entries cause of posting to different G/L Account
Hi, I have known that Dynamics NAV has the "Reverse Transaction" function in order to correct already posted journal entries but is there a way to just correct them and make them gone from the General Ledger Entries? Cause when our other division wanted to check the Credit and Debit of the accounts separately and reconcile them to our bank accounts, it will show up as un-match reconciliation because of the addition of "unwanted" entries on the account. Thank you! Karl Steven
↧
↧
Forum Post: RE: DateFormula Variable
lDate := TODAY; MESSAGE('Before: %1',TODAY); DFormula := '-2M'; lDatenew := CALCDATE(DFormula,lDate); MESSAGE('Aftre : %1',lDatenew); Name DataType Subtype Length DFormula Text 30 lDate Date lDatenew Date
↧
Forum Post: RE: BUSINESS CENTRAL - HOW TO REFRESH FACTBOX CHART
Hi Fernando, Can you kindly mention the page and also the Factbox that you are trying to refresh? Is this a PowerBI chart? If yes, then click on the title of the Factbox where it says "PowerBI Reports" and click Refresh Page: Thank you, Mohamad
↧
Forum Post: RE: Error - this prefix cannot be used on DataFormula
You should check what values is passed to PeriodLength variable.
↧
Forum Post: RE: Page - Field property set to FALSE but still showing by default
Changing the VISIBLE property to false is the correct way to hide this field and permit to the end user to set visible when he wants. So strange that you can't make it work. Are you sure that there's no code that change the field visibility dinamically? have you correctly deployed your object?
↧
↧
Forum Post: Option Fields Index Value
Hi I have Option DataType with values 0,30,60,90 . If user selects 30 i want to get value as 1. If user selects 90 then value should be 3. Thanks
↧
Forum Post: RE: Using Mobile NAV 2016
Check Service Tier Event Log to get the exact error message and share that.
↧
Blog Post: Cognitive Entity API services with AL: Did you mean ….?
AI and Cognitive. All the Azure Cognitive Services (and google Cloud AI too, I guess) have a common key behavior: They give us an API URL direction and give us API keys when we subscribe them. We make an API call with a human being input: image, video, sound, text in natural language or no serialized. The service analyzes this input and returns the analysis results in a JSON output. Transform anarchical input into actionable information with a regular computer. Cognitive Entities service. Cognitive is a set of Artificial intelligence services in Microsoft Azure. Cognitive Entity not the most impressive Cognitive service (but accidentally I find a very interesting feature: auto-correction). Cognitive Entities Is a Knowledge database with tv shows, movies, places, celebs and organizations. I have a fictitious example: my customer is an electronics retailer. He has a media department with movies, tv shows, music records and games. We offer an experiment: use Cognitive Entity to process item master table. When the employee types the item description, Cognitive Entity automatically brings us this information: Item category: Movie, tv show, record, game, etc. Load item picture in the card. Bring a long description of the item to check it. Also, it is possible to type descriptions and batch this process later to fill this information. So, If I type in description “ Mad men ” I get this card: The good stuff of this cognitive service is transform anarchical Bing searching output into a JSON format, allowing us to extract the data with simple tags: Item category is “ entityTypeHints ” , picture URL is “ hostPageUrl ” and the long description of the entity is in tag “ description ” . Example code breakdown. In the item Card Page, when I validate description, call “ GetEntityInfo ” function to bring all the information I need. local procedure GetEntityInfo ( ) var JSONBuffer : Record "JSON Buffer" Temporary ; begin CallJSONEntity ( JSONBuffer ) ; JSONBuffer . GetPropertyValue ( EntityDescription , 'description' ) ; SetItemPicture ( JSONBuffer , ' hostPageUrl ' ) ; SetItemCategory ( JSONBuffer , ' entityTypeHints ' ) ; CheckDescription ( JSONBuffer ) ; CurrPage . Update ( false ) ; end ; I Fill a JSON Buffer with the function “ CallJSONEntity ” : not a great deal, only an API call with the subscription key of Cognitive Entities. local procedure CallJSONEntity ( var JSONBuffer : Record "JSON Buffer" Temporary ) var ClienteHttp : HttpClient ; RequestEntity : HttpRequestMessage ; Cabecera: HttpHeaders ; Respuesta: HttpResponseMessage ; url: Text ; TextoRespuesta : Text ; begin url : = 'https://api.cognitive.microsoft.com' + '/ bing /v7.0/entities' + '? mkt =es-ES' + '&q=' + Description ; RequestEntity . SetRequestUri ( Url ) ; RequestEntity . Method ( 'GET' ) ; RequestEntity . GetHeaders ( Cabecera ) ; Cabecera . Add ( ' Ocp - Apim -Subscription-Key' , subscriptionKey ) ; if not ClienteHttp . send ( RequestEntity , Respuesta ) then Error ( ' Call failed ' ) ; Respuesta . Content . ReadAs ( TextoRespuesta ) ; JSONBuffer . ReadFromText ( TextoRespuesta ) ; end ; - Call a remote API and the API returns JSON format. - I put this JSON into a JSON buffer. - In URL field we add Spanish market label (mkt=es-ES) and my question (following “ &q= ” ): item description content. After this call I can get values from JSON, and fill then Item record values. The smartest feature: Did you mean Minecraft? This is real: I don ’ t know anything about video-games and I notice that almost always I mistyped the item description when I was testing this feature. By example, I always type “ Main craft ” instead “ Minecraft ” . Fortunately, most of the time API returns me the right information. It transforms bad description into right description for searching and returns it in JSON with the property “ alteredquery ” . Then, I make an auto-correct feature (classic search engines “ Did you mean ” feature): The code is very simple, only get another property form JSON object: local procedure CheckDescription ( var JSONBuffer : Record "JSON Buffer" temporary ) var RightDescription : Text ; begin JSONBuffer . GetPropertyValue ( RightDescription , ' alteredQuery ' ) ; if RightDescription = '' then exit ; if Confirm ( SugestionQ , true, Description, RightDescription ) then Description : = RightDescription ; end ; Get image function. Not the subject of the post, but here you are the code to get the image from Entities. There is a very interesting feature in “ TemBlob ” table, “ TryDownloadFromURL ” function. local procedure SetItemPicture ( var JSONBuffer : Record "JSON Buffer" temporary ; SeachLabel : text) var tempBlob : Record TempBlob temporary ; URLImage : Text ; begin JSONBuffer . GetPropertyValue ( URLImage , SeachLabel ) ; if URLImage <> '' then TempBlob . TryDownloadFromUrl ( URLImage ) ;
↧
Forum Post: RE: Option Fields Index Value
There are a few ways you can do this. 1) Using OptionCaption and Option String properties OptionCaption 0,30,60,90. OptionString 0,1,2,3 2) Create a function and call the function when you want to get a value. GetOptionValue() CASE field OF field::0 : EXIT(0); field::30 : EXIT(1); field::60 : EXIT(2); field::90 : EXIT(3); END;
↧
↧
Forum Post: RE: Page - Field property set to FALSE but still showing by default
Is the behavior only happened on specific fields ? What about other fields ? Try choose columns and restore to default.
↧
Forum Post: RE: Deleting General Ledger Entries cause of posting to different G/L Account
You should not delete your gl entries. You will have problems with your system and audit later. Try to prevent the mistake on the first place.
↧
Forum Post: RE: DateFormula Variable
NewDate := CALCDATE(DateFormula,CurrDate); docs.microsoft.com/.../calcdate-function--date-
↧
Forum Post: RE: Error - this prefix cannot be used on DataFormula
You can't assign negative on the Period Length because it is not a number value. Try to change what you want to accomplish, or train user to put negative date formula when inputting the field.
↧
↧
Forum Post: RE: Page List - Add totals to a list from a header table
Why do you want to make it within the list ? You can put it in the page similar to general journal's balance. If you want it to be inside the list, you need to make the list as temporary table, and insert the record into it. It will be much harder to do that.
↧
Forum Post: RE: Sales Invoice Line Already Exists Error
There shouldn't be any issue with standard NAV posting. Try checking if there is any customization done on the posting logic.
↧
Forum Post: RE: After Windows Security updates an Access Denied error message pops up when using Dynamics NAV Web Client via Internet Explorer
One of our customers has this issue and it is vital for their operation.
↧