Obtain Salesforce Session Id through Visualforce, Anonymous Apex, or Cookie Retrieval (and avoid SESSION_ID_REMOVED)
Tags: salesforce, apex, visualforce
Published: 2020-07-31 01:20:08

The Salesforce Session Id is a token representing a user's authenticated session, and must be used to make API calls as that user, such as this example using `curl`:

```bash
curl https://my_domain.my.salesforce.com/services/data/v47.0/ -H 'Authorization: Bearer 00D000000000abc!ABcABCDp0ABCdeZgn30EabcFpg7.v.xyzxO_abcEqh7PLqYY4Ea6XBV.ab5ct07AB4cp.5jDEFHtDaHTp_ABCfgFkhF8P7EQ'
```

Replace "my_domain" with your Salesforce org's My Domain, and replace the fake Session Id with the real one, and you should see a list of service endpoints in JSON.

> **Security bulletin**

> If you are copying out your Session ID, leaving it in logs, your clipboard, your command-line history, or even your code, do yourself a favor and _*log out of Salesforce*_ as soon as you are done with your API work. Once logged out, the Session Id is invalid, so session hijacking using that Session Id is impossible. Until that point, though, you are vulnerable. And, of course, do not commit your Session Id to version control (such as git).

There are three ways I have used to obtain the Session Id: a Visualforce page, Anonymous Apex in Developer Console, or, my favorite, retrieving a cookie from the browser using a bookmarklet.

## Using a Visualforce page with `$Api.Session_ID`

I sometimes make a Visualforce page that displays the Session Id. Something like this works fine:

```html
<apex:page>
{!$Api.Session_ID}
</apex:page>
```

I usually label it "0SessionId" so that it appears at the top of this list in Setup -> Visualforce Pages. Of course, make sure the Name does not start with a number, due to the sacred laws of Salesforce API names.

Why stop there? The following page makes it fairly convenient to copy out the Session Id.

```html
<apex:page showHeader="false">
<html>
<head>
  <title>Session Id for {!$Organization.Name}</title>
  <style>
      input {
        font-family: monospace;
        width: 112ch;
      }
  </style>
  <script>
      function copyId() {
        var idField = document.getElementById("sfsessid");
        idField.select();
        document.execCommand("copy");
      }
  </script>
</head>
<body>
  <p><input id="sfsessid" size="112" type="text" value="{!$Api.Session_ID}"></input></p>
  <p><button onclick="copyId()">Copy Session Id</button></p>
</body>
</html>
</apex:page>
```

After page creation, click the Quick Save then the Preview button to find the Session ID. I don't recommend installing this as a Visualforce tab; just preview the page when you need the Id.

## Using Anonymous Apex in the Developer Console and `UserInfo.getSessionId()`

In the Developer Console, press Ctrl/Cmd-e to launch the Anonymous Apex window. One would think the following would work well:

```java
System.debug(UserInfo.getSessionId());
```

But after executing, the debug logs show `SESSION_ID_REMOVED` rather than the Session ID. This is a security feature. We would not want to leave this key to our user session lying around in our logs.

### Anonymous Apex Solution #1: mangle the Session ID

If you are convinced leaving Session Ids in your debug logs is an acceptable risk, you can try mangling them just enough for Salesforce to leave them alone. For instance, try splitting the Session Id with a space somewhere in the middle:

```java
void sessIdSplit() {
	String sessId = UserInfo.getSessionId();
	System.debug(sessId.substring(0,50) + ' ' + sessId.substring(50));
}

sessIdSplit();
```

Copy it out of the debug log, then remove the space before using it.

Not terribly convenient or secure.

### Anonymous Apex Solution #2: place the Session ID in a private Note

For this option, first make sure the [new Notes feature is enabled](https://help.salesforce.com/articleView?id=notes_setup_enable.htm&type=5) in your org.

```java
void sessIdNote() {
    ContentNote cn = new ContentNote();
    cn.Title = 'Session Id for ' + UserInfo.getName() + ' ' + System.now().format();
    cn.Content = Blob.valueOf(UserInfo.getSessionId());
    cn.SharingPrivacy = 'P';
    insert cn;
}

sessIdNote();
```

Now, in the App Switcher, select Files, and you should see a note with the Session Id in the content. Blank out the content and delete it when you are done, and, once again, log out of Salesforce to invalidate the Session Id.

### Anonymous Apex Solution #3: place the Session ID in a Task

```java
void sessIdTask() {
    String userId = UserInfo.getUserId();
    Task t = new Task();
    t.OwnerId = userId;
    t.Subject = 'Session Id for ' + UserInfo.getName() + ' ' + System.now().format();
    t.Status = 'Open';
    t.Priority = 'Normal';
    t.Description = UserInfo.getSessionId();
    insert t;
}

sessIdTask();
```

This is similar to the Note solution above, but with a Task in case you don't have Notes enabled. When all done using the Session Id, blank out the Task description (you might cut instead of copy), mark it complete, and logout.

## Retrieving a cookie with Javascript in a bookmarklet

This is the one that I use and love. Convenient, and more secure than the above solutions.

Bookmarklets reside in your bookmarks, and allow you to execute arbitrary Javascript on any web page you choose.

Install the one I wrote below. You can trust me.

Yeah... Maybe you should understand what it does first.

The following snippet, once you feel good about it, can be selected and dragged to your bookmarks bar

```javascript
javascript:(() => {let apipath='/services/data/'; if (location.pathname === apipath) {let sessid = (';' + document.cookie).split("; sid=")[1].split("; ")[0];  navigator.clipboard.writeText(sessid);} else {window.open(location.origin + apipath, "_blank");}})();
```

Once there, you first login to your Salesforce org, then click the bookmarklet. You will usually need to click it twice (once after the redirect).

Here is a prettier version:

```javascript
javascript: (() => {
  let apipath = "/services/data/";
  if (location.pathname === apipath) {
    let sessid = (";" + document.cookie).split("; sid=")[1].split("; ")[0];
    navigator.clipboard.writeText(sessid);
  } else {
    window.open(location.origin + apipath, "_blank");
  }
})();
```

The bookmarklet, once clicked, will check if the current page is the Salesforce services endpoint for this org. If it is not, it will redirect to that endpoint so that we can be ensured that we are on the correct subdomain for future API calls. Once there, the bookmarklet needs to be clicked again, and it will find the cookie with the name "sid" and copy the value (the Session Id) to the clipboard.

Do you need a bookmarklet? Not necessarily. You can open the Chrome DevTools Console, select the Application tab, expand Cookies and copy out the sid cookie. Just make sure you are on the same domain that you intend to make API calls to, so you get the right cookie.

Again, when you are done with the Session Id, it is a good idea to logout of Salesforce.

Enjoy your Salesforce API calls.