You are here:
Create an Embedded Login Server-Side Callback
Use the server-side callback instead of a client-side callback web page to avoid exposing the access token on the client. To create a server-side callback, use the OAuth 2.0 web server flow.
Embedded Login relies on third-party cookies, which are blocked or restricted in most browsers. And Embedded Login works only on Google Chrome and only as long as third-party cookies are allowed there by default.
When you use the server-side callback, create a separate servlet that implements the web server flow using the OAuth 2.0 authorization code grant type.
Use these steps to create the server-side callback servlet.
- Implement the web server flow. For detailed steps to implement this flow, see OAuth 2.0 Web Server Flow for Web App Integration.
-
Create the OAuth response that the Embedded Login posts after successfully receiving an
access token.
The response must contain these meta tags.
- salesforce-community
- salesforce-mode (where the value ends in -callback)Note The value of the salesforce-mode meta tag is the same mode specified in the Embedded Login web page with the -callback suffix. For example, if salesforce-mode on the web page is set to modal, the value is modal-callback.
- salesforce-server-callback (where the value must be
true) - salesforce-server-response
- salesforce-server-starturlNote If the Block Redirect to Unknown URL setting is enabled for the site, Salesforce blocks redirects to unknown URLs that are provided in the state parameter of the OAuth response. Redirects are allowed when the URL is in the same host or domain as the site, or is allow-listed in the Embedded Login salesforce-allowed-domains meta tag.
- salesforce-target
- salesforce-allowed-domains
You can include the salesforce-save-access-token with the valuetrueto save the access token after initialization. By saving the access token, you can continue to interact with Salesforce during the active user session. -
In your Embedded Login web page, specify these meta tags.
-
Add the salesforce-server-callback meta tag with the value
true. This meta tag indicates that the callback to handle the HTTP response is on the server.<meta name="salesforce-server-callback" content="true"> -
Make sure that the salesforce-redirect-uri meta tag references the location of the
server-side callback servlet. Use the same URL as specified in the callback URL field
of your Embedded Login external client app.
<meta name="salesforce-redirect-uri" content="https://embeddedlogin.heroku.com/servlet/servlet.serversidecallback> - Make sure that the salesforce-mode on this web page matches the mode on the server-side callback.
-
Add the salesforce-server-callback meta tag with the value
package servlet;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.json.JSONObject;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.*;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
@WebServlet(
name = "CallbackServlet2",
urlPatterns = {"/_callback"}
)
public class ServerSideCallbacks extends HttpServlet{
// Client ID
private static final String CLIENT_ID=
"3MVG9xOCXq4ID1uF8V6oKd32SPVi6FHwEOQlQ5BjvaKX.5QZpGe4Z3F4fc6KvMYsQ.fi314cp0oZ8KpOBs4Mh";
// client secret
private static final String CLIENT_SECRET = "9103416584217247123";
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws
ServletException, IOException {
String code = request.getParameter("code");
if (code != null) {
code = URLDecoder.decode(code, "UTF-8");
}
String startURL = request.getParameter("state");
if (startURL != null) {
startURL = URLDecoder.decode(startURL, "UTF-8");
}
String tokenResponse = null;
String communityUrl = null;
HttpClient httpclient = new HttpClient();
try {
// community_url parameter passed from redirect uri.
communityUrl = request.getParameter("sfdc_community_url");
// Token endpoint : communityUrl + "/services/oauth2/token";
PostMethod post = new PostMethod(communityUrl+"/services/oauth2/token");
post.addParameter("code",code);
post.addParameter("grant_type","authorization_code");
// Consumer key of the external client app.
post.addParameter("client_id", CLIENT_ID);
// Consumer Secret of the external client app.
post.addParameter("client_secret",CLIENT_SECRET);
// Callback URL of the external client app.
post.addParameter("redirect_uri",
"https://boiling-brushlands-41143.herokuapp.com/_callback");
httpclient.executeMethod(post);
tokenResponse = post.getResponseBodyAsString();
post.releaseConnection();
System.err.println("tokenResponse: " + tokenResponse);
} catch (Exception e) {
throw new ServletException(e);
}
JSONObject identityJSON = null;
try {
JSONObject token = new JSONObject(tokenResponse);
// get the access token from the response
String accessToken = token.getString("access_token");
String identity = token.getString("id");
httpclient = new HttpClient();
GetMethod get = new GetMethod(identity + "?version=latest");
get.setFollowRedirects(true);
get.addRequestHeader("Authorization", "Bearer " + accessToken);
// get identity information using the access token
httpclient.executeMethod(get);
String identityResponse = get.getResponseBodyAsString();
get.releaseConnection();
identityJSON = new JSONObject(identityResponse);
identityJSON.put("access_token", accessToken);
} catch (Exception e) {
throw new ServletException(e);
}
response.setContentType("text/html; charset=utf-8");
PrintWriter out = response.getWriter();
// Notice that we’re using base64 encoded
String outputStr = "<html><head>\n" +
"<meta name=\"salesforce-community\" content=\""+ communityUrl +"\">\n" +
// notice the -callback in the salesforce-mode content value
"<meta name=\"salesforce-mode\" content=\"modal-callback\">\n" +
"<meta name=\"salesforce-server-callback\" content=\"true\">\n" +
// send the identity information back to the Embedded Login
"<meta name=\"salesforce-server-response\" content='" +
Base64.getEncoder().encodeToString(identityJSON.toString().
getBytes(StandardCharsets.UTF_8))+"'>\n" +
"<meta name=\"salesforce-server-starturl\" content='" + startURL +"'>\n" +
"<meta name=\"salesforce-target\" content= \"#salesforce-login\">\n"+
"<meta name=\"salesforce-allowed-domains\"
content=\"boiling-brushlands-41143.herokuapp.com\">\n" +
"<script src=\""+ communityUrl +
"/servlet/servlet.loginwidgetcontroller?type=javascript_widget\"" +
" async defer></script>\n" +
"</head><body></body></html>";
out.write(outputStr);
}
}

