function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
jkucera2jkucera2 

Apex OAuth 2.0 Example

I'm an OAuth noob and strugging to get a login page to pop up where Apex is the client and GoToWebinar is the Service.  How do I make the login screen pop up?  Does it somehow magically take over the VF page via redirect or do I need some javascript to open a new window?  Below is my attempted approach using HttpRequest:

 

My first attempt is something like this:

public class G2WButtonController{
    public G2WButtonController(ApexPages.StandardController stdController){
    }
    
    //Code that will run upon button click
    public void autoRun(){
        callG2W(args);
    }

    public static void callG2W(String[] args) 
    {
        String postURL='https://api.citrixonline.com/oauth/authorize?client_id=<myClientId>';
        Http http = new Http();
        HttpRequest req = new HttpRequest();
        req.setEndpoint(postURL);
        req.setMethod('POST');
        HttpResponse res = http.send(req);

        //Class to parse the results
        XmlStreamReader reader = res.getXmlStreamReader();
    }
}

 VF

<apex:page standardController="G2W_Login__c" extensions="G2WButtonController" action="{!autoRun}">
  <apex:pagemessages />

    <apex:sectionHeader title="Auto-Running Apex Code"/>
  <apex:outputPanel >
      You tried calling Apex Code from a button.  If you see this page, something went wrong.  You should have
      been redirected back to the record you clicked the button from.
  </apex:outputPanel>

</apex:page>

 Once I get the login page to pop up, I'm assuming I would then parse the HttpResponse to get a param from the redirect URL- is that correct?

 

Any code samples others have would be greatly appreciated!

Best Answer chosen by Admin (Salesforce Developers) 
jkucera2jkucera2

Update for anyone that finds this later.  I learned I was approaching the problem wrong - I need to redirect to the URL with my aurthorization ID as a param and include a return URL that points to the VF page so that the controller can grab the param returned in the VF redirect URL and then make a server side post to get the access token, refresh token, and userId in the service provider.  

 

I'm still not 100% sure how to securely store the access token, refresh token, and userId that the other app returns, but I'm guessing a custom setting might better than a custom object as its less discoverable.  Not sure if sharing can be set to private on it though to minimize prying eyes. 

All Answers

jkucera2jkucera2

Update for anyone that finds this later.  I learned I was approaching the problem wrong - I need to redirect to the URL with my aurthorization ID as a param and include a return URL that points to the VF page so that the controller can grab the param returned in the VF redirect URL and then make a server side post to get the access token, refresh token, and userId in the service provider.  

 

I'm still not 100% sure how to securely store the access token, refresh token, and userId that the other app returns, but I'm guessing a custom setting might better than a custom object as its less discoverable.  Not sure if sharing can be set to private on it though to minimize prying eyes. 

This was selected as the best answer
DHO_604DHO_604

I'm having the same problem as you!  Would you be able to shed some light on the code to get the pop up and redirect back to my page?

jkucerajkucera

I punted on the idea of a pop up and instead just had my VF page button redirect that page to the 3rd party site, which then returns to the same VF page after authorization.

 

No need to use the same VF page for the button & redirect, but I wanted to show the confirmation on the same page.

 

I'm not experienced enough to know how to have a pop up talk back to another browser tab, so this approach was easier for me and provides a decent customer experience too.

DHO_604DHO_604

Gotcha, thanks!

DHO_604DHO_604

Wondering if you can shed some light on how to capture the code from the redirect after the user enter his credentials, when the user is redirect back to the VF page?

 

Cheers!

jkucerajkucera
String returnedParameterName='code';
PageReference pageref=ApexPages.currentPage();
String param=pageRef.getParameter(returnedParameterName);

 

http://www.salesforce.com/us/developer/docs/pages/index_Left.htm#StartTopic=Content/apex_pages_pagereference.htm?SearchType=Stem

DHO_604DHO_604

Hi John,

 

Thanks for the snippet.  I used a javascript button to call the authorization page, but don't know how to detect the redirect back to my VF page.  Is there some kind of listener or event trigger out there that does this?  Or is my approach incorrect?

 

Thanks so much!

jkucerajkucera

The flow for the service provider I'm authenticating to requries the redirect URL as part of the initial request.  

 

I don't have the syntax at hand, but it was something like:

 

https://api.<serviceprovider>.com/oauth/authenticate?clientId=<myAppsId>&redirect=<full URL for my vf page>

 

They then add the param to my redirect url after the user authorizes access.

DHO_604DHO_604

Hi John,

 

That's the exact syntax I have too.  After the user enters his credentials and clicks on 'Allow Access' then the user is redirected back to <full URL for my vf page>

 

The problem is that how do I detect that the user is done and the redirect has happened, and execute the rest of my code? The pageRef works if I'm calling the the authorization page within a class.  Here is the sequence of events

 

1. User clicks on Javascript button on VF Page

2. Javascript sends user to authorization page on the same page (no popups)

3. User enters credentials and clicks on allow access

4. user is redirected back to <full URL for my vf page> with code= XXXXX tagged to the end of the URL

5. Detect redirect (how do you do this?)

6. Execute the rest of the code

 

I'm stuck on step 5. If the approach is correct.

 

Thanks again!

jkucerajkucera

You don't "detect the redirect", you have the redirct point to a VF page and have an autorun method grab any param in the URL.  If the URL contains the "success code", then you know it succeeded and you got there as a result of the redirect.

DHO_604DHO_604

Bingo. Thanks John!

nagalakshminagalakshmi

Hi,

 

I am also trying for the same thing. But i am getting bad request error. Could you please post the sample code if you dont mind.. Please help me..

 

Thanks,

Lakshmi

jkucerajkucera

Something like this:

public with sharing class oAuthPageController{

    public PageReference authenticateOAuth(){
        return new PageReference(<your 3rd party oAuth URL>);
    }//authenticateOAuth
    
    public void autoRun(){
        //This method checks if the responseKey is in the URL as a param, and if so, 
        //gets the Access token, refresh token, and other info for this user from the 3rd party tool
        PageReference pr=ApexPages.currentPage();
        Map<String, String> params=pr.getParameters();
        String responseKeyParamName='code';//will be a different param name for you
        String responseKey;
        if(params.size()>0){
             if (params.get(responseKeyParamName)!=null){
                ResponseKey=params.get(responseKeyParamName);
                Boolean success=someOtherClass.accessTokenURL(responseKey);//This makes a callout to grab the token using the responseKey and the client secret
                if(success=TRUE){
                    ApexPages.Message confirmation=new ApexPages.Message(ApexPages.severity.CONFIRM, 'Confirmed: It worked');
                    ApexPages.addmessage(confirmation);
                }
             }//if 2
        }//if 1
    }//autoRun
}

 

nagalakshminagalakshmi

Hi John,

 

i got the error while i am using your code..

 

I got the error at this line someOtherClass.accessTokenURL(responseKey);

 

And i have used the code like 

 

public class gotowebinaroauth
{
public string res1{set;get;}
private string session;
string code{set;get;}
public boolean frame{set;get;}
public gotowebinaroauth()
{
frame=false;
session = userInfo.getSessionId();
system.debug(session +'sss==');
code=apexpages.currentpage().getparameters().get('code');
if(code!=null)
second();
system.debug(code+'code===');
}
public pagereference detail()
//public void detail()
{
frame=true;
Http h = new Http();
HttpRequest req = new HttpRequest();
final string username = 'username here';
final string password = 'welcome1';
Blob headerValue = Blob.valueOf(username + ':' + password);
//String authorizationHeader = 'BASIC ' +EncodingUtil.base64Encode(headerValue);
String authorizationHeader = 'OAuth' +EncodingUtil.base64Encode(headerValue);
req.setHeader('Authorization',authorizationHeader);
//req.setHeader('Authorization', 'OAuth ' );
//req.setHeader('Host','https://api.citrixonline.com/oauth/authorize?client_id=7ce8c52e2cbe09c32a9ddc09f1894ac3');
//req.setHeader('Host','https://api.citrixonline.com/oauth/authorize?client_id=7ce8c52e2cbe09c32a9ddc09f1894ac3&redirect_uri=http://www.dskvap.com/');
//req.setHeader('Host','https://api.citrixonline.com/oauth/authorize?client_id=be77d883448f4e585805ab7873c40cda&redirect_uri=http://www.dskvap.com');
req.setHeader('Host','https://api.citrixonline.com/oauth/authorize?client_id=87f1f7a08282efd61bb0bd9f045ce1fd&redirect_uri=https://c.ap1.visual.force.com/apex/gotowebinaroauth');
req.setHeader('Connection','keep-alive');
req.setHeader('Content-Type', 'application/json;charset=UTF-8');
req.setMethod('GET');
//req.setEndpoint('https://api.citrixonline.com/oauth/authorize?client_id=7ce8c52e2cbe09c32a9ddc09f1894ac3');
//req.setEndpoint('https://api.citrixonline.com/oauth/authorize?client_id=7ce8c52e2cbe09c32a9ddc09f1894ac3&redirect_uri=http://www.dskvap.com/');
//req.setEndpoint('https://api.citrixonline.com/oauth/authorize?client_id=be77d883448f4e585805ab7873c40cda&redirect_uri=http://www.dskvap.com');
req.setEndpoint('https://api.citrixonline.com/oauth/authorize?client_id=87f1f7a08282efd61bb0bd9f045ce1fd&redirect_uri=https://c.ap1.visual.force.com/apex/gotowebinaroauth');

HttpResponse res = h.send(req);
res1=res.getbody();
system.debug('********'+res.getbody());

pagereference p=new pagereference('https://api.citrixonline.com/oauth/authorize?client_id=87f1f7a08282efd61bb0bd9f045ce1fd&redirect_uri=https://c.ap1.visual.force.com/apex/gotowebinaroauth');
return p;
}
string s1;
string s2;
public void second()
{
s1=apexpages.currentpage().getparameters().get('code');
s2 = s1.remove('=');
system.debug(s2+'s2==');
Http h = new Http();
HttpRequest req = new HttpRequest();
final string username = 'username here;
final string password = 'welcome1';
Blob headerValue = Blob.valueOf(username + ':' + password);
String authorizationHeader = 'BASIC ' +EncodingUtil.base64Encode(headerValue);
//String authorizationHeader = 'OAuth' +EncodingUtil.base64Encode(headerValue);
req.setHeader('Authorization',authorizationHeader);
req.setHeader('Authorization', 'OAuth ' );
req.setHeader('Host','https://api.citrixonline.com/oauth/access_token?grant_type=authorization_code&code='+s2+'&client_id=87f1f7a08282efd61bb0bd9f045ce1fd');
req.setHeader('Connection','keep-alive');
req.setHeader('Content-Type', 'application/json;charset=UTF-8');
req.setMethod('POST');
req.setEndpoint('https://api.citrixonline.com/oauth/access_token?grant_type=authorization_code&code='+s2+'&client_id=87f1f7a08282efd61bb0bd9f045ce1fd');

 

HttpResponse res = h.send(req);
res1=res.getbody();
system.debug('********'+res.getbody());

}

}

 

 

<apex:page controller="gotowebinaroauth">
<apex:form >
<apex:commandButton value="Get Details" action="{!detail}"/><br/>

<apex:outputText value="{!res1}"></apex:outputText>

</apex:form>
</apex:page>

 

I am getting the error as, Bad request error. I have tried a lot but not getting.. Can you help me please..

 

Thanks,

Lakshmi

 

jkucerajkucera

Looks like you are trying to pass the username/pw, which kinda defeats the whole purpose of oAuth (to protect those).  

The flow I recommend is supposed to be like this:

1) User clicks on VF tab

2) My Autorun method in the VF controller fires on page load. If there's no param (there wouldn't be at this point), then nothing happens

3) User clicks button on VF page.  This is the URL of your app's oAuth flow.  For GoToWebinar, I'd guess this is passing a new PageRef with a param for your app's Id

4) User should see a username/pw login screen & logs in

5) User approves the app

6) If you set up the app properly, it should redirect to your VF page with some parameters for success.  In my example, the param was called "code"

7) On VF page load, the same AutoRun method fires again, checking for this param.  Since it exists, it then sends that param to another method, which makes an API call to get the access token & refresh token. 

Kartik GuptaKartik Gupta

Hi John,

 

I am using a trigger that calls a class which prepares the JSON to be sent to the Google Calendar API v3.

I'm trying to bypass the OAuth 2.0 pop-up that comes, maybe by using a static key or using the 'Connected App' option.

 

Please guide which is the best way and how to proceed further.

 

Thanks,

Kartik

jkucerajkucera

Kartik - can you email me?  I'd like to better understand what you're desired experience is here.  I'm just getting up to speed on how connected apps work relative to oAuth but hopefully can point you in the right direction.

 

We're looking at implementing a Google contact import (safe harbor) using a similar library and the flow we'll use is something like:

  1. Prospect clicks "connect"
  2. Link opens up a pop up initiating the Google oAuth flow (link contains our app's Id)
  3. Prospect clicks "approve" to grant access
  4. Pop up returns the code to the page, then closes
  5. We use the code to make calls to Google

I might be missing a step in #5 to exchange the auth code for an access token but don't have time to check right now.

 

btw-email is jkucera at salesforce dot com.