---
schema_version: "1"
id: 3ad5cba636a37b76ed6367e9fbef20b8a698a73ceb915fe7d25971afa42d0e98
title: Create an Embedded Login Server-Side Callback
collection: admin
version: current
locale: en-us
portal_url: https://docs.salesforce.com/admin/current/en-us/xcloud/264-0-0/external_identity_login_server_callback.md
canonical_url: https://help.salesforce.com/s/articleView?id=xcloud.external_identity_login_server_callback.htm&release=264.0.0&type=5
source_site: help.salesforce.com
content_type: documentation
content_hash: b51989e41a167218f8d0c1a687abca6cfe93d454963c7f8a19ea4c929c5d0f7d
description: 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.
products:
  - Security
  - Cross Cloud
release: "264"
---
# 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.

![Warning](https://sf-zdocs-cdn-prod.zoominsoftware.com/tdta-xcloud-identity-264-0-0-production-enus/699dab6f-8f1a-4662-b24f-6521d5b747f7/images/icon_warning.png)

Warning In Summer ’24, Salesforce made Embedded Login disabled by default. We recommend that you use the [web server flow](https://help.salesforce.com/s/articleView?id=xcloud.remoteaccess_oauth_web_server_flow.htm&type=5&language=en_US), the [user-agent flow](https://help.salesforce.com/s/articleView?id=xcloud.remoteaccess_oauth_user_agent_flow.htm&type=5&language=en_US), or another redirect-based OAuth 2.0 flow instead of Embedded Login.

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.

1. Implement the web server flow. For detailed steps to implement this flow, see [OAuth 2.0 Web Server Flow for Web App Integration](https://help.salesforce.com/articleView?id=xcloud.remoteaccess_oauth_web_server_flow.htm&type=5&language=en_US).
2. 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](https://sf-zdocs-cdn-prod.zoominsoftware.com/tdta-xcloud-identity-264-0-0-production-enus/699dab6f-8f1a-4662-b24f-6521d5b747f7/images/icon_note.png)
        
        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-starturl
        
        ![Note](https://sf-zdocs-cdn-prod.zoominsoftware.com/tdta-xcloud-identity-264-0-0-production-enus/699dab6f-8f1a-4662-b24f-6521d5b747f7/images/icon_note.png)
        
        Note 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 value `true` to save the access token after initialization. By saving the access token, you can continue to interact with Salesforce during the active user session.
3. In your Embedded Login web page, specify these meta tags.
    1. 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">`
    2. 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>`
    3. Make sure that the salesforce-mode on this web page matches the mode on the server-side callback.

![Example](https://sf-zdocs-cdn-prod.zoominsoftware.com/tdta-xcloud-identity-264-0-0-production-enus/699dab6f-8f1a-4662-b24f-6521d5b747f7/images/icon_example.png)

Example

![Note](https://sf-zdocs-cdn-prod.zoominsoftware.com/tdta-xcloud-identity-264-0-0-production-enus/699dab6f-8f1a-4662-b24f-6521d5b747f7/images/icon_note.png)

Note This server callback servlet uses base64 encoding in the server response.

```javascript
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);
    }

}
```