Loading
Salesforce now sends email only from verified domains. Read More
Identify Your Users and Manage Access
Table of Contents
Select Filters

          No results
          No results
          Here are some search tips

          Check the spelling of your keywords.
          Use more general search terms.
          Select fewer filters to broaden your search.

          Search all of Salesforce Help
          OAuth 2.0 Asset Token Flow for Securing Connected Devices

          OAuth 2.0 Asset Token Flow for Securing Connected Devices

          To integrate IoT devices with the Salesforce API, use the OAuth 2.0 asset token flow. Asset tokens are an open-standards-based JWT authentication token for verifying and securing requests from connected devices. Asset tokens identify the device to a backend service that processes the stream of data and events from the device. These tokens allow registration of device data with the Salesforce platform and linking the device to Salesforce CRM data about the customer, account, or contact.

          Required Editions

          Available in: both Salesforce Classic and Lightning Experience
          Available in: All Editions
          Note
          Note Connected apps creation is restricted as of Spring ‘26. You can continue to use existing connected apps during and after Spring ‘26. However, we recommend using external client apps instead. If you must continue creating connected apps, contact Salesforce Support.

          See New connected apps can no longer be created in Spring ‘26 for more details.

          Devices—via connected apps—use the OAuth 2.0 asset token flow to request an asset token from Salesforce. In this flow, an OAuth access token and an actor token are exchanged for an asset token. This flow combines asset token issuance and asset registration for efficient token exchange and automatic linking of devices to Service Cloud Asset data.

          For example, your customer purchases a connected device and registers an account with your support site. Your company offers a mobile app that acts as an agent for device registration. A connected app allows the user to connect to the device, log in to your support site, and register the device. In exchange for an access token and an actor token, your site issues an asset token that identifies the device to your backend cloud service.

          After registration, the device can operate independently of the connected app, routinely sending data about its state and operations to your backend service. If the backend proactively detects an abnormal behavior or state, it automatically creates a case. The case is associated with the asset, which is tied directly to the customer’s contact record and your company’s support process. The device can also signal that an office supply, such as ink toner, is low, potentially identifying a new market opportunity.

          The OAuth 2.0 asset token flow involves these general steps.

          1. Configure a connected app to issue asset tokens for connected devices. See Enable OAuth Settings for API Integration.
          2. The connected app requests an access token from the Salesforce token endpoint.
          3. After Salesforce grants an access token, the connected app requests an asset token using the OAuth 2.0 token exchange protocol.
          4. If the asset token JWT is valid, Salesforce grants an asset token and registers the device.
          5. Salesforce publishes an asset token event.

          Request an Access Token

          For a connected app to issue an asset token for the connected device, it first invokes an OAuth 2.0 flow to request an access token. After receiving the access token, the connected app exchanges it for an asset token, which it requires for device registration.

          Note
          Note To demo the asset token flow, use the Asset Token Explorer demo app. See Demo the Asset Token Flow

          Common methods for getting access tokens include the OAuth 2.0 web-server flow and the OAuth 2.0 JWT bearer flow. With a browser and a utility such as cURL, you can get and exchange an authorization code as follows.

          1. In a browser, go to this URL after you substitute the placeholder values. https://your_site_url/services/oauth2/authorize?response_type=code&client_id=your_client_id&​redirect_uri=your_url_encoded_redirect_uri
          2. Log in and approve your app.
          3. When you receive a callback, get the authorization code. Replace it along with the other placeholder values in exchange for an access token.
            curl -s -k -d
                            "grant_type=authorization_code&code=authorization_code&redirect_uri=
                            your_url_encoded_redirect_uri&client_id=your_client_id&client_secret=your_client_secret"
                            https://your_site_url/services/oauth2/token
                          

          Request an AssetToken

          After receiving an access token, the connected app posts an asset token request to the Salesforce token endpoint, using the OAuth 2.0 token exchange protocol.

          Here’s a sample request posted to the Salesforce token endpoint using an unsigned actor token.

          POST /services/oauth2/token HTTP/1.1
          Host: customersite.my.site.com
          Content-Type: application/x-www-form-urlencoded
          
          grant_type=urn:ietf:params:oauth:grant-type:token-exchange&
          subject_token_type=urn:ietf:params:oauth:token-type:access_token&
          subject_token=0DB00001iSr!AR0AQDhXv4xNCYPUwRa3_KyiZxNgNmrJU7QPJUrvBRM9x
          3MLnlEbOOsuldLL.3mb.nML1h8G8zAc2zkUU_q.HEM6bY0kOJjDL&
          actor_token_type=urn:ietf:params:oauth:token-type:jwt&
          actor_token=eyJhbGciOiJub25lIiwidHlwIjoiSldU In0.eyJkaWQiOiI4NTc4OTliOS02OTk4LTQzZD
          QtODQ4My0xOTRlODBkNzE4Y2MiLCJBc3NldFRva2VuQ3VzdG9tQXR0cmlidXRlX19jIjoiTXkgVmFsdWUiLC
          JBc3NldCI6eyJOYW1lIjoiRGlzaHdhc2hlciIsIlNlcmlhbE51bWJlciI6IjEyMzQ1Njc4In19.
          

          The request includes these parameters:

          Important
          Important When developing OAuth integrations, always pass sensitive information in the body of a POST request or in a request header. Don't use GET parameters in the URL query string to pass sensitive information. Sensitive information includes but isn't limited to usernames, passwords, OAuth tokens, client secrets, and any personally identifiable information. For more information on security best practices, see Storing Sensitive Data in the Secure Coding Guide.
          Parameter Description
          grant_type Use these values for the grant type: urn:ietf:params:oauth:grant-type:token-exchange.
          subject_token_type Required. Value must be urn:ietf:params:oauth:token-type:access_token.
          subject_token Required. The subject token is a security token that represents the identity of the user for whom the request is being made. For asset tokens, the value is the access token.
          actor_token_type Optional unless actor_token is specified. Value must be urn:ietf:params:oauth:token-type:jwt.
          actor_token Optional. The actor token, which is a security token, represents the identity of the user who is authorized to use the requested security token and act on behalf of the subject. For asset tokens, the value is a JWT that contains metadata about your new or existing asset. If your use case requires Proof of Possession, you can include a confirmation key and sign the actor token. Otherwise, it can be unsigned.

          Actor Token Payload

          The actor token payload is a JWT containing a set of claims about the device you’re registering. All claims are optional. If you don’t pass any of this metadata, Salesforce can still issue your asset token, but it can’t register the device at the same time.

          This example actor token payload includes an asset claim.

          {
            "did": "2c4c73e7-edc5-77dd-011d-43562d21cb7e",
            "Name": "My Asset Token",
            "cnf": {
              "jwk": {
                "kty": "RSA",
                "e": "AQAB",
                "use": "sig",
                "alg": "RS256",
                "n": "AJNGcu8nW6xq2l_dAgbJmSfHLGRn-vCuKWY-LAELw-Kerjaj5Dq3ZGW38HR4BmZksG3g4eA1RXn1hiZGI1Q 6Ei59QE_OZQx2zVSTb7-oIwRcDHEB1-RraYT3LJuh4JwUDVfEj3WgDnTjE5vD46l_CR5EXf4VL8uo8T40FkA
          51AhT"
              }
            },
            "Asset": {
              "Name": "Asset 19730",
              "SerialNumber": "9461094121",
              "AccountId": "001D000000KtKgS",
              "MyCustomAssetField__c": "Depreciated"
            }
          }
          

          You can include these claims in the actor token payload.

          Claim Description
          did The ID of the device. If included, it’s saved and returned in the issued asset token.
          Name Name of the asset token.
          cnf Confirmation containing a device-specific RSA public key in JSON Web Key format, which is defined in the Proof-of-Possession Key Semantics for JSON Web Tokens specification. If included, the actor token must be signed with the private key corresponding to the public key.
          Asset Asset JSON object containing any valid fields from the asset object, including custom fields. If included, it’s used to link to an existing asset by ID or serial number, or to create an asset with the specified name.
          exp Expiration. If included, it’s used to validate that the JWT hasn’t expired.
          Actor Token JWT

          After constructing your actor token payload, create the actor token JWT. The format depends on whether the actor token is unsigned or signed. Unsigned actor tokens carry claims for registering the asset without a corresponding device public key. Signed actor tokens let you include a public key in the resulting asset token. The device uses the public key to prove possession of the private key, ensuring the token is used by the device it was issued to.

          Here’s a sample unsigned actor token:

          eyJhbGciOiAibm9uZSJ9.eyAiZGlkIiA6ICIzNDk2NDMzMS04YTZjLTRmODYtYjM0Zi0zMjI3ZWExZjU1MDk iLCAiTmFtZSIgOiAiMzQ5NjQzMzEtOGE2Yy0Zjg2LWIzNGYtMzIyN2VhMWY1NTA5IiwgIkFzc2V0IiA6IHs
           gIk5hbWUiIDogIk15IENvbm5lY3RlZCBEZXZpY2UiLCAiU2VyaWFsTnVtYmVyIiA6ICIzNDk2NDMzMS04YTZ jLTRmODYtYjM0Zi0zMjI3ZWExZjU1MDkiLCAiQWNjb3VudElkIiA6ICIwMDFEMDAwMDAwS3Uwd0UiIH0gfQ.

          Which decodes into a header of:

          {"alg": "none"}
          

          And a payload of:

          {
            "did": "34964331-8a6c-4f86-b34f-3227ea1f5509",
            "Name": "My Asset Token",
            "Asset" : {
              "Name" : "My Connected Device",
              "SerialNumber" : "349643 1-8a6c-4f86-b34f-3227ea1f5509",
              "AccountId" : "001D000000Ku0wE"
            }
          }
          

          There’s no signature block.

          An unsigned actor token has a header with a single alg claim. The algorithm claim indicates that no signature is applied to the JWT. The value must be none.

          The signature block is an RSA SHA256 signature of header.payload. that is base64url encoded and appended to the JWT. This signature on the JWT must be verifiable using the public key provided in the cnf claim. If valid, the public key is saved to the asset token event record and included in the cnf claim in the returned asset token JWT.

          Here’s a sample signed actor token:

          eyJhbGciOiAibm9uZSJ9.eyAiZGlkIiA6ICIzNDk2NDMzMS04YTZjLTRmODYtYjM0Zi0zMjI3ZWExZjU1MDk iLCAiTmFtZSIgOiAiMzQ5NjQzMzEtOGE2Yy0Zjg2LWIzNGYtMzIyN2VhMWY1NTA5IiwgIkFzc2V0IiA6IHs gIk5hbWUiIDogIk15IENvbm5lY3RlZCBEZXZpY2UiLCAiU2VyaWFsTnVtYmVyIiA6ICIzNDk2NDMzMS04YTZ
           jLTRmODYtYjM0Zi0zMjI3ZWExZjU1MDkiLCAiQWNjb3VudElkIiA6ICIwMDFEMDAwMDAwS3Uwd0UiIH0gfQ. DLVM9EGvZ1VasMSzPbi7mviIXucvTktfOTYq62cTVduSsLKR4gX3Q8xfm85SfqoMaCQVXLNGkZ1iYv5LjJ4_ e69yl9r5gIML7qHDwQOSqgsNYd8HPK4qpX­v1QMzBCRXCNenqQ0YhJbokCPWeH­WWnPNGFYuquKL2fTTmczadTo

          The actor token decodes into this header:

          {
            "typ": "JWT",
            "alg": "RS256"
          }
          

          The actor token also decodes into this payload:

          {
            "cnf": {
              "jwk": {
                "kty": "RSA",
                "e": "AQAB",
                "use": "sig",
                "alg": "RS256",
                "n": "AJNGcu8nW6xq2l_dAgbJmSfHLGRn-vCuKWY-LAELw-Kerjaj5Dq3ZGW38HR4BmZksG3g4eA1RXn1hiZGI1Q 6Ei59QE_OZQx2zVSTb7-oIwRcDHEB1-RraYT3LJuh4JwUDVfEj3WgDnTjE5vD46l_CR5EXf4VL8uo8T40FkA
          51AhT"
              }
            },
            "did": "34964331-8a6c-4f86-b34f-3227ea1f5509",
            "Name": "My Asset Token"
          }
          

          A signed actor token has a header with these claims:

          Claim Description
          alg Algorithm claim to identify the signature algorithm. Value must be RS256.
          typ Type claim identifies the type of token. Value must be JWT.

          Salesforce Grants an Asset Token

          If the actor token JWT is valid, the access token response from Salesforce contains a success message and returns your asset token. For example:

          HTTP/1.1 200 OK
                Date: Wed, 06 Jan 2017 21:25:11 GMT
                Expires: Thu, 01 Jan 1970 00:00:00 GMT 
                Pragma: no-cache 
                Cache-Control: no-cache, no-store,s-maxage=0 Content-Type: application/json;charset=UTF-8
                {
                "access_token":"eyJraWQiOiJBc3NldHMiLCJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOl siaHR0cDovL2xvY2FsaG9zdDo1MDAwIl0sIm5iZiI6MTQ1MjExNTUxMSwiaXNzIjoiaHR0cHM6Ly9hc3NldG lkLWRldmVsb3Blci1lZGl0aW9uLm5hMS1ibGl0ejAzLnNvbWEuZm9yY2UuY29tIiwiaWQiOiIwNWJEMDAwMD AwMDAwMUiLCJleHAiOjE0NTI2MzM5MTEsImFpZCI6IjAyaUQwMDAwMDAxNkdESyIsImRpZCI6IjM0OTY0Mz MxLThNmMtNGY4Ni1iMzRmLTMyMjdlYTFmNTUwOSJ9.poVKl-fBrFi9tgKurAM2vbyGWZ5asbXJ5nQlfA CsStFnksKiS14gD9_oK9RchHsLlAt3gSCkIXtdFMmHDPQECtfpvhXhCBw-FAYLNnhJVivU7oNimiUzEVhYlw
                -p7V3Qr2lmPzhXzEisELWuQgkyfABdiI9PUOjJA3rLb6RSBmCSA5sjkYKlCjnxRcMA9ZExgS5134yq_bPR V9BTrDwy2O34Ml2VwGjl9kIMWa5v8CHEtP7eMHbJpqgHQXpwnPna0ND4kAr7EQGF1zuIUBJMS35ZyZYtw5Eg da1QbYm8TGpRaKP7tiB0GL1_i3MhGeEC8qnlXg6pWuhJd_Q",
                "issued_token_type":"urn:ietf:params:oauth:token-type:jwt",
                "token_type":"Bearer",
                "expires_in":51840
                }
              
          Note
          Note The access_token parameter contains your issued asset token. The expires_in parameter represents the validity length that you specified in your connected app.

          The asset token JWT returned within the access token response contains a header, payload, and, if signed, a signature.

          Here’s a sample signed asset token:

          eyJraWQiOiJBc3NldHMiLCJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOlsiaHR0cDovL2x
          vY2FsaG9zdDo1MDAwIl0sIm5iZiI6MTQ1MjUzNzUyMCwiaXNzIjoiaHR0cHM6Ly9hc3NldGlkLWRldmV
          sb3Blci1lZGl0aW9uLm5hMS1ibGl0ejAzLnNvbWEuZm9yY2UuY29tIiwiY25mIjp7Imp3ayI6eyJrdHk
          iOiJSU0EiLCJlIjoiQVFBQiIsImtpZCI6ImRldmljZWtleSIsIm4iOiJoUHBlM1RqYkJTMHB2dzFoMGQ
          zbWxqdkNsOVp4Uk9YNzhRNEhLUGVPQjBPWml3QzBaSXBtaHdWZGRQeWFxYklVdTJvcUJORkc3S2Q4YVM
          zMDJtQVlkLXNuQzdIcnlzekd1YzIwOFIyMUVMTGJwZ2dWOUlKdl9zdnRMNXh4UjlUdjBfUFRBNFUyR0h
          VbnE1dFdDTlNqVEhoYkNzWHNrSmlLSWN4MHR3N2tJMmNaR01VQTJvakEyb1U1YkFrSDYyUkNBUTNEcDl
          xTktoNldxZlI3VUpyQlV6NTFuaHVEcnE5eTFRWE1RX3pNZENXLTVTUEFMTE3ekRJa2oyX3FSdmR6LUJQ
          SFRPYkU4WXg3cGFlenYzS0hZa3prRHd1M3hqUGhEZGtXMURXMWFraC1zdVpQcFl3STl4bDJ6RUNJMVU1
          UVdmT0szeTIwTW1jSEFtRXhtQXIyRHcifX0sImlkIjoiMDViRDAwMDAwMDAwMDVCIiwiZXhwIjoxNDUz
          MDU1OTE3LCJhaWQiOiIwMmlEMDAwMDAwMTZHTWciLCJkaWQiOiIyYzRjNzNlNy1lZGM1LTc3ZGQtMDEx
          ZC00MzU2MmQyMWNiN2UifQ.Bi-CJGeOUPibvw73oZN26fNM4wEjX1XF657s9dzAgJZCXZlFps4Atu-4H
          eILBnnkEkGJPLhSLm88nWcANPIFVNQKkAEifQtUjj2QE7AIWdzoFC9RuyxFv0HnAwRYkJuqoE5en3HV9
          8qWMxh1-J3m0eFRTS1tUPSnrKnnPvHktuH4TdRpi3RTl3bueXmgUdYeIXNcpG71wRZDheEGxK_p5Uejq
          1YmZVz1a6TBAZG3bH5sJhO0ygk1eHlHwzc5Q0yEH7cI_T5wv7puu_TTiGpDFiWwOcnvsBA8Kf8-LWEaP
          Ku6Aypgbg3Ii3kY6RQEQaeTYpd8Q_jSlJi7IwQIA5WbLA

          The asset token decodes into this header:

          {
            "kid": "00D300000000mlxEAA.978",
            "typ": "JWT",
            "alg": "RS256"
          }
          

          The asset token also decodes into this payload:

          {
            "aud": ["https://your.devicebackend.com"],
            "sub": "005WS000001c17CMJP",
            "nbf": 1452537520,
            "iss": "https://yoursite.com"
            "cnf": {
              "jwk": {
                "kty": "RSA",
                "e": "AQAB",
                "use": "sig",
                "alg": "RS256",
                "n": "hPpe3TjbBS0pvw1h0d3mljvCl9ZxROX78Q4HKPeOB0OZiwC0ZIpmhwVddPyaqbIUu2oqBNFG7Kd8aS302mA Yd-snC7HryszGuc208R21ELlbpggV9IJv_svtL5xxR9Tv0_PTA4U2GHUnq5tWCNSjTHhbCsXskJiKIcx0tw7 kI2cZGMUA2ojA2oU5bAkH62RCAQ3Dp9qNKh6WqfYwUJrBUz51nhuDrq9y1QXMQ_zMdCW-5SPALM17zDIkj2_ qRvdz-BPHTObE8Yx7paezv3KHYkzkDwu3xjPhDdkW1DW1akh-suZPpYwI9xl2zECI1U5QWfOK3y20MmcHAmE xmAr2Dw"
              }
            },
            "id": "05bD0000000005B",
            "exp": "1453055917"
            "aid": "02iD00000016GMg",
            "did": "2c4c73e7-edc5-77dd-011d-43562d21cb7e"
            "custom_attributes": {
              "customattribute1": "unfiltered",
            }
          }
          

          The asset token header contains these claims.

          Claim Description
          kid Key ID claim identifies the org-specific public key associated with your connected app. It’s used to verify the signature block in a signed actor token.
          alg Algorithm claim to identify the signature algorithm. Value must be RS256.
          typ Identifies the type of token. Value must be JWT.

          The asset token JWT payload contains these claims.

          Claim Description
          iss Issuer claim identifies the JWT issuer, which can be an Experience Cloud site URL, a My Domain login URL, or a custom domain URL.
          aud Audience claim identifies who the JWT is intended for. Value is an array of case-sensitive strings, each containing a StringOrURI value. An audience is specified for each intended consumer of the asset token.
          sub Subject claim identifies the 18-character, case-insensitive ID of the current user of the JWT.
          exp Expiration time claim identifies the time when the JWT can no longer be processed. Value must be a numeric value representing the number of seconds from 1970-01-01T00:00:00Z UTC until the specified UTC date/time, ignoring leap seconds.
          nbf Not before claim identifies the time before the JWT can be processed. The processing of the nbf claim requires that the current date/time must be after or equal to the not-before date/time listed in the nbf claim. Value must be a numeric value representing the number of seconds from 1970-01-01T00:00:00Z UTC until the specified UTC date/time, ignoring leap seconds.
          did Device ID claim represents the ID for your device. If the actor token included a did claim, it’s included in the asset token.
          aid Asset ID claim represents the ID of the new or existing asset that the access token is linked to.
          cnf Confirmation claim contains a device-specific RSA key in JSON Web Key format, as defined in the Proof-of-Possession Key Semantics for JSON Web Tokens specification. It’s used to verify Proof of Possession of the device’s private key.
          Additional claims Additional claims can include custom attributes or custom permissions that you specified in your connected app.

          Asset Registration

          Salesforce attempts to link the asset token to an existing asset or to create an asset, using this decision model.

          1. If the asset claim contains an ID claim, Salesforce attempts to link to an existing asset with a matching ID.
          2. If the asset claim contains a serial number claim, Salesforce attempts to link to an existing asset with a matching serial number.
          3. If the asset claim contains a name claim, Salesforce creates (registers) an asset.
            Note
            Note Creating an asset requires an asset AccountId or ContactId.
          4. Otherwise, Salesforce doesn’t link to or create an asset. You can separately link an asset later, via the API.

          Salesforce Publishes an Asset Token Event

          If the actor token and access token are exchanged for an asset token, Salesforce publishes an asset token event. For more information about the AssetTokenEvent object and an example of how to trigger an action after an asset token event, see AssetTokenEvent.

           
          Loading
          Salesforce Help | Article