Salesforce to SharePoint - Part Two - Complete Authentication Part in Salesforce

Introduction 

 
The main issue for the topic of this article was saving the security token. Since I am new to Salesforce, I have used the trial version of trailhead and trial o365 tenant. The only configuration I did on salesforce is to add remote site settings. In the below approach, you can see that I have used a simple button to make a REST callout every time. In Approach 1, I have used the GetJWT to get access_token, deserialize it, and pull the access_token from the JSON response. Then pass it to the HTTP Callout with sample POST request.

Note
The access token being generated was approximately 1100 chars.

I was researching where to store the Client secret, client ID. Then I stumbled upon a lot of options, shown below.
  • Custom Settings - No way to store the 1000 chars. Fields limited to 255 chars.
  • Custom Metadata Types - This was the best option for me, since these support long fields. But I thought the implementation of these was a bit complex. I will post the code below which will basically read and write to a custom metadata type. Also every time to update a value, it would use a deploy container which didn’t mean anything because I am a SharePoint guy. ;) (there is deployment done every time we need to update the value (code sample below).

Controller

  1. public class SPSFOAuthController {  
  2.     public final List VATs {  
  3.         get;  
  4.         set;  
  5.     }  
  6.     final Map VATsByApiName {  
  7.         get;  
  8.         set;  
  9.     }  
  10.     public SPSFOAuthController() {  
  11.         VATs = new List();  
  12.         VATsByApiName = new Map();  
  13.         for (SPSFOAuth__mdt v: [SELECT QualifiedApiName, MasterLabel, Accesstoken__c  
  14.                 FROM SPSFOAuth__mdt  
  15.             ]) {  
  16.             VATs.add(v);  
  17.             VATsByApiName.put(v.QualifiedApiName, v);  
  18.         }  
  19.     }  
  20.     public PageReference save() {  
  21.         // Create a metadata container.      
  22.         Metadata.DeployContainer container = new Metadata.DeployContainer();  
  23.         List vatFullNames = new List();  
  24.         for (String recordName: VATsByApiName.keySet()) {  
  25.             vatFullNames.add('SPSFOAuth.' + recordName);  
  26.         }  
  27.         List records = Metadata.Operations.retrieve(Metadata.MetadataType.CustomMetadata, vatFullNames);  
  28.         for (Metadata.Metadata record: records) {  
  29.             Metadata.CustomMetadata vatRecord = (Metadata.CustomMetadata) record;  
  30.             String vatRecordName = vatRecord.fullName.substringAfter('.');  
  31.             SPSFOAuth__mdt vatToCopy = VATsByApiName.get(vatRecordName);  
  32.             for (Metadata.CustomMetadataValue vatRecValue: vatRecord.values) {  
  33.                 vatRecValue.value = vatToCopy.get(vatRecValue.field);  
  34.             }  
  35.             // Add record to the container.      
  36.             container.addMetadata(vatRecord);  
  37.         }  
  38.   
  39.         // Deploy the container with the new components.      
  40.         Id asyncResultId = Metadata.Operations.enqueueDeployment(container, null);  
  41.         return null;  
  42.     }  
  43. }  
VFP
 

Object

 
There must be field-level permissions set on this. I was leaning towards this because it was very simple to insert an object from the apex class.
 
We just need to create a custom object, instantiate it, then set a value to the custom field. I even tried encrypting the field and we have a long (more than 2000 something chars) field available. Everything seems easy, except for the fact that I wanted to have something more robust and secure.
 
Named Credentials
 
I initially saw in all the blog posts, that named credentials were the way to go but, it didn’t have SharePoint authentication mentioned, and I had no idea that I could create one. So I have used named credentials and boyyy was it awesome. Wait for it……….It handled all the authentication for Oauth by itself………………….whaaaaaaaa!!!!!
 
If you see the section Working code Approach - 1, this was not using any storage for access_token. Check the difference using named credentials in Working code Approach.
 
Keep in mind that SharePoint REST handles Oauth in two ways, which can be differentiated by the grant type. I will add this inside the SharePoint block, since it would make more sense for it to be there.
 
Grant Type - Client_Credentials
Grant_type - authorization_code
  • Refer to this page for details about the auth.
  • Create Auth. Provider in Salesforce
  • Now I have started with Named credentials. I followed many blogs in creating the Auth. Provider for SharePoint.
I will provide a step by step guide below to implement Named Credentials for Oauth SharePoint SalesForce integration. I really think that the cloud has made everything easier for us developers…..
 
Create Auth. Provider.Navigate to Setup > Identity >Auth. Providers(or search for auth providers)
 
Click the new button. Select provider type as Microsoft Access Control Service. The fields populate.
 
Follow the steps from Salesforce help. First, create the Auth. provider with empty placeholders. This will generate a couple of URLs as Salesforce Configuration. It should look like below.
 

IMP

 
Make a note of the callbackurl. This URL should be entered inside the redirect URL when registering the SharePoint “app-only”
 
 
I think that is it for creating Auth. Provider.
 
Create Named Credentials using the custom auth provider.
 
Navigate to named credentials. Setup>Security.
 
Click on New Named Credential. Enter the label of your choice. The same name is populated and can be changed as per need.
 
URL needs to be the SharePoint URL without any endpoints. I was making the mistake of adding the _api/web/lists and all. But it just needs to be the site collection without any REST endpoints.
 
Select Named Principal for Identity Type.
 
OAuth 2.0 for Authentication Protocol.
 
And the Authentication provider is the one that we created in the previous step.
 
I didn’t specify any scopes, but I also need to research more on this. In Salesforce, we can add custom scopes and salesforce suggests we don’t mess with any existing scopes. Some blogs mentioned to use list.write. But I have just given full permission while registering the app.
 
Check the Start Authentication Flow on Save.
 
Now Callout Options; this is important because I use this callout to send data through the apex. The goal is to have salesforce generate access_token for us without us explicitly calling every time. 
  • Checkmark both Generate Authorization Header and Allow Merge Fields in HTTP Header.
You can refer to all the options in the below image.

Once you click on save, it would take you to the SharePoint page and you can click on trust this app.
 
It will successfully return the Named credentials page with the Authentication Status as Authenticated. BOOOMMMM!!
  • Issues Troubleshooting :
  • Unauthorized: This was caused because I unchecked the Generate Authorization header. Let Salesforce generate the authorization header. You can see in apex the headers in the below code approach 2.
  • Unsupported Media Type: This was caused because I unchecked allow merge fields for the HTTP header. Make sure the content type is allowed by JSON.
  • Invalid grant_type: I came across this issue. It will mostly have to do with incorrect client id or client secret or the bearer token or the auth code. Cross verify each and all the fields to the ones that you have created in SharePoint and in Salesforce Auth provider.