Quantcast
Jump to content


Report

  • Similar Topics

    • By Samsung Newsroom
      From winning the CES 2026 Best of Innovation Award to being named one of TIME magazine’s “Best Inventions of the Year,” Samsung’s Micro RGB TV has earned global recognition. Building on its debut as the world’s first Micro RGB TV, Samsung Electronics is expanding the lineup this year with a 130-inch ultra-large model, setting a new benchmark for next-generation television technology.
      From adopting micro-size RGB (red, green and blue) LEDs as a backlight unit to pursuing enhanced color expression and integrating AI technology for ultra-large displays, the development of the Micro RGB TV was a continuous series of firsts — with virtually no reference points to guide the process.
      Samsung Newsroom spoke with Insang Hwang of the Visual Display (VD) Business Division’s Product Planning Group to learn more about how this new category of the Micro RGB TV was developed.
      ▲ Micro RGB TV recognized for its technological excellence in the global market.
      Creating a New Category With No Reference
      The Micro RGB TV began as a project to create an entirely new category in the TV market. Hwang recalled, “Because the mission was to create a category that didn’t previously exist, every department — from development to sales and marketing — had to work together with a shared sense of urgency and responsibility.”
      One of the biggest challenges was the absence of any reference point. The team had to develop new technologies and products from scratch while simultaneously defining the value they could deliver to consumers. “We went beyond simply applying RGB light sources,” he said. “We developed a proprietary concept called ‘Micro RGB,’ which miniaturized even the backlight unit itself to the micro level.”

      Pursuing 100% BT.2020 — The “Ultimate Color Gamut”
      At the core of the Micro RGB TV is its color reproduction. By applying RGB LEDs as the backlight unit, the display achieves wide and highly accurate color reproduction.
      “Although the Micro RGB TV started with the goal of delivering richer color reproduction, there was no clearly defined industry standard at the time,” Hwang said. “We felt a strong sense of responsibility, believing that the conditions we set could become the new standard for the market. That’s why we set the ambitious goal of achieving ‘100% BT.2020’ — the ultra-high-definition color standard defined by the International Telecommunication Union (ITU) and often referred to as the ‘ultimate color gamut.’”
      ▲ Micro RGB TV achieves 100% BT.2020 — the “ultimate color gamut” — setting a new standard in the TV market. Achieving 100% BT.2020 means that a level of color reproduction once limited to professional monitors can now be experienced on TVs — one of the most widely used displays in everyday home environments. It also marks a significant advancement in the technical standards of the display industry.
      The journey, however, was far from easy. “In the early stages of development, we struggled to reach the target values,” Hwang recalled. “However, through persistent efforts to achieve perfect color reproduction, the development team was ultimately able to meet its goal.” He added, “It wasn’t just about developing new technology. We also worked to establish measurable standards to validate its performance.”

      Bringing Cutting-Edge Technology Into Everyday Viewing
      For product planners, the top priority is to convert advanced technology into an experience that users can easily perceive in everyday life. “We continuously thought about how to translate Micro RGB’s powerful hardware performance into a practical viewing experience,” Hwang said. “We focused on making its key strength — color — something users can feel naturally in everyday content while delivering an immersive viewing experience.”
      “While Micro RGB achieves one of the highest color gamuts available in TVs today, only a limited amount of content fully utilizes it,” he noted. “So we enhanced software capabilities to ensure users can experience the difference across a wider range of content — from HDR content to everyday content such as OTT streaming and sports.”
      One of the key features is Micro RGB Color Booster Pro. Hwang explained, “Leveraging a high-performance neural processing unit (NPU), AI analyzes content in real time to enhance color expression with precision. This allows users to enjoy Micro RGB’s vivid color performance not only in HDR content but also in everyday viewing.”
      ▲ Hwang explained that Micro RGB Color Booster Pro enhances color for a richer and more vivid viewing experience. He added, “For example, in soccer — one of the sports most frequently watched on TVs — the newly introduced AI Soccer Mode Pro automatically detects the content and enhances colors such as the grass and team uniforms. With the global football season kicking off in June, it’s a feature worth noting for those seeking a more immersive viewing experience.”
      In addition, the TV incorporates a Glare Free feature designed for real-world viewing environments. “We applied glare-free technology so users can consistently enjoy Micro RGB’s exceptional color performance regardless of lighting conditions,” Hwang explained. “Whether in a dark room or a brightly lit space, viewers can stay fully immersed without reflections interfering with the screen.”

      Scaling Immersion With a 130-Inch Display
      The newly introduced 130-inch ultra-large model delivers an overwhelming sense of immersion, as if the entire wall comes to life. As screen size increases, maintaining image detail becomes increasingly critical.
      Hwang said, “We equipped the TV with Supersize Picture Enhancer, an AI-powered picture quality technology optimized for ultra-large displays. Thanks to this, viewers can enjoy Micro RGB’s rich colors and sharp image quality without distortion or pixelation.”
      The sound experience and design were also significantly enhanced. “With a 160W 10.4.2-channel speaker system, the TV delivers immersive sound that fills the entire space without the need for external speakers,” he added.
      ▲ Micro RGB TV features a wall-mount design that integrates seamlessly with the space, enhancing immersion. The Micro RGB TV’s signature wall-mount design further reinforces immersion by blending the display seamlessly into its surroundings. “We developed a proprietary pocket structure and wall-mount bracket1 so the TV can sit flush against the wall with virtually no gap,” Hwang explained. “We focused on delivering an optimized viewing experience for ultra-large screens across picture quality, sound and design.”

      Toward the Next-Generation Screen Experience
      The Micro RGB TV goes beyond technological advancement — it expands the boundaries of how users experience screens in everyday life while setting new standards for the industry.
      “Samsung TVs are evolving into screens that seamlessly integrate into users’ lifestyles and living spaces, understanding their preferences through data and enabling interactions,” Hwang said. “They will go beyond content consumption to become powerful platforms that connect limitless experiences and services.”
      As the Micro RGB TV continues to push the boundaries of innovation, Samsung is paving the way for the next generation of screen experiences.
      Applicable to 85-, 75- and 65-inch models only ︎ View the full article
    • By Samsung Newsroom
      Galaxy Store Seller Portal is Samsung's platform for developers to publish and manage their applications in Galaxy Store. It provides tools for submission, distribution, analytics, and release control.
      Galaxy Store is a gateway to millions of Samsung device users, and for a developer, the stakes of a release can be incredibly high: A minor bug in a major update can lead to negative reviews and churn. To mitigate this, Samsung provides the Staged Rollout feature.
      A staged rollout allows developers to gradually release application updates to only a certain percentage of users. This controlled approach helps developers manage releases efficiently and observe application behavior during update deployment. Instead of distributing an update to all users at once, developers can define a rollout percentage and increase it over time.
      Key Benefits
      Here are the key benefits of using a staged rollout strategy:
      Control release distribution Identify issues early Reduce the risk of large-scale failures Monitor real-world performance The staged rollout rate can be set from 0% to 100%, where 0% means the update is not available at all and 100% indicates a full release. Galaxy Store provides flexibility by allowing developers to manually control and adjust rollout percentages based on performance and feedback.
      Staged rollouts are supported for Android applications and can be configured based on the application’s status in Seller Portal. The appStatus parameter is central to every staged rollout API call. Find out more at Status Parameters Mapping.
      Managing Staged Rollouts Using the Content Publish API
      While staged rollouts can be configured through the Seller Portal UI, the Content Publish API provides a powerful programmatic interface to automate your application’s lifecycle. Within this framework, the Staged Rollout API functions as a specialized suite of endpoints that allow developers to manage incremental distribution through code rather than manual intervention.
      End-to-End Flow (Example)
      Before jumping into the API description, it is important to understand the full workflow.
      The following illustrates a typical staged rollout workflow using the Content Publish API:
      Upload Binary → Create or Update Application Content → Configure Staged Rollout (Initial Rate) → Submit for Publication → Rollout Begins (Partial Distribution) → Monitor Rollout Status → Update Rollout Rate (Progressive Increase) → (Optional) Update Rollout Binary → Complete Rollout (Full Distribution)
      This flow represents a common implementation pattern. Actual workflows may vary depending on your release process. For another example of a staged rollout workflow, see Staged Rollout Release.
      This tutorial focuses on the four essential endpoints that form the backbone of an automated, controlled release workflow: View Staged Rollout Rate, Update Staged Rollout Rate, View Staged Rollout Binaries, and Update Staged Rollout Binary. Each of these endpoints provides the granular control necessary to ensure that your updates reach your Galaxy device users with maximum stability and minimum risk.
      Prerequisites
      Before making any Content Publish API calls, you must satisfy the following requirements set out in the Galaxy Store Developer API documentation:
      A registered Seller Portal account. Commercial seller status Registered applications in Seller Portal Service account ID from Seller Portal A valid access token generated using the authentication endpoint. Every API call must include this token in the Authorization: Bearer header. For more information about access tokens, check out this article. Python installed on your PC. Starting the Implementation
      Before implementing the APIs, it is helpful to understand the basic structure of the code. In this example, Python is used for API implementation.
      The basic code structure is as follows:
      Dependency Library → Headers → Application Information → Payload → API Endpoint → CRUD Operation.
      Dependency Library
      To use Python script for HTTP requests, import the requests library. At this point, also import the json library to see the response in the JSON format.
      # Importing the requests library import requests # Importing the json library import json Headers
      To call any Content Publish API, an access token and service account ID must be sent with the headers for user authorization.
      Headers parameters are:
      Attribute
      Type
      Description
      Authorization
      string
      Bearer <your-access-token>
      service-account-id
      header
      Your service account ID
      Now, set the required values for these headers using Python:
      # Access token and headers accessToken = "<your-access-token>" Authorization = "Bearer " + accessToken SERVICE_ACCOUNT_ID = "<your-service-account-id>" # Header to be sent to the API headers = { 'Content-Type': 'application/json', 'Authorization': Authorization, 'service-account-id': SERVICE_ACCOUNT_ID } Since the dependency libraries and headers are common across all requests, you have to define them first to implement the Content Publish API.
      NoteEvery Content Publish API request requires two authorization headers: Authorization: Bearer <your-access-token> and service-account-id: <your-service-account-id>. Missing either of these headers returns an authentication error. Implementing the “View Staged Rollout Rate” Endpoint
      This endpoint retrieves the current default rollout rate as well as any country-specific rollout rates for the given application.
      Application Information
      It is essential to provide the following details for the View Staged Rollout Rate operation:
      # Content ID and app status contentId= '<Content ID of your app>' appStatus= 'REGISTRATION' Here, contentId is the unique identifier of your application in Seller Portal. In the appStatus parameter, you can use either REGISTRATION or SALE. REGISTRATION is for the version under registration/update, and SALE is for the currently live version.
      These parameters are required to accurately specify the application for which the staged rollout information is being requested.
      API Endpoint
      Use the following API to consume the application staged rollout rates.
      # Defining the API endpoint (GET request) api_url=f"https://devapi.samsungapps.com/seller/v2/content/stagedRolloutRate?contentId={contentId}&appStatus={appStatus}" GET Operation
      Finally, send an HTTP GET request to the Galaxy Store Server with the api_url and headers parameters.
      This is a read-only operation to inspect the state of a rollout.
      try: response = requests.get(api_url, headers=headers) print("Status Code:", response.status_code) data_shows = response.json() print("Parsed JSON:", json.dumps(data_shows, indent=4)) except Exception as e: print("Error:", str(e)) Response on Success
      After processing the request, if all the provided information is correct, then the operation returns the success response in the JSON format:
      Status Code: 200 Parsed JSON: { "resultCode": "0000", "resultMessage": "Ok", "data": { "rolloutRate": 40, "countries": [ { "countryCode": " AUT ", "rolloutRate": 30 }, { "countryCode": "BEL", "rolloutRate": 45 }] } } The rolloutRate object at the top level is the global default rate. The countries object contains possible country-specific rates that override the default. In this example, the application is being rolled out to 40% of users globally, to 30% in Austria, and to 45% of users in Belgium.
      Implementing the “Update Staged Rollout Rate” Endpoint
      Updating a staged rollout in Seller Portal refers to modifying the current rollout rate to expand application availability to a larger percentage of users. The updated rollout rate must be higher than the previously set value and is applied progressively during the distribution process.
      The following figure shows the UI from Seller Portal. You can change most of the settings shown using the Update Staged Rollout API.

      https://d3unf4s5rp9dfh.cloudfront.net/GlxyStore_blog/2026-05-28-01-01.jpg Figure 1: Update Staged Rollout Rate user interface



      On this screen, if you enable the Staged Rollout Settings option, the rollout settings portion is enabled and you can set the rollout rate. Otherwise, the option to do so remains unavailable.
      The Content Publish API allows you to manage distribution either globally or with regional precision.
      Default Rollout Rate: This is the primary percentage applied to all supported countries. If no specific country data is provided, every market receives the update at this baseline rate.
      Country-Specific Rollout Rate: This allows you to override the default rollout rate for individual markets. You can set a different rollout rate for each country.
      In Figure 1, from the Seller Portal UI, you can see that the default rollout rate is 40%, the Austrian rate is 30%, and the Belgian rate is 45%. Here, the 40% default rate is applicable for all other countries except Austria and Belgium. During the release, Austria and Belgium will follow their customized rollout rate.
      To modify the rollout rate for a specific country, your request has to contain either new or updated rates for any existing countries you have already defined (in the given example, Austria and Belgium) before you can add new ones. Otherwise, the request returns an error response. If you want to change the default rate only, then you can omit the countries object from the code.
      API Endpoint
      Define the API endpoint for updating the default or country specific staged rollout rate.
      # Defining the API endpoint (PUT request) api_url="https://devapi.samsungapps.com/seller/v2/content/stagedRolloutRate" Payload
      The payload defines the new rollout configuration to update the existing rollout settings. Here, when the appStatus is SALE or you are updating a previously deployed app, the new rolloutRate must be greater than the previously set default rollout rate. You cannot decrease a rollout rate once set for a live app. Plan your incremental ramp-up carefully before you start.
      The payload contains the JSON data which are required for updating an application’s rollout rates.
      # Payload (ENABLE rollout) payload = { "contentId": " <Content ID of your app>", "function": "ENABLE_ROLLOUT", "appStatus": "REGISTRATION", "rolloutRate": 50, "countries": [ { "countryCode": "AUT", "rolloutRate": 30 }, { "countryCode": "BEL", "rolloutRate": 55 }] } } In this example, the code changes the default rollout rate from 40% to 50% and the country-specific rollout rate for Belgium from 45% to 55%.
      You can set the function value as either “ENABLE_ROLLOUT” or “DISABLE_ROLLOUT” to enable or disable the staged rollout settings. If you disable the setting, you cannot change the value.
      For this call to be successful, the appStatus field must be set. Setting it with the value “REGISTRATION” during an update indicates that the application content is being modified and prepared for submission.
      PUT Operation
      Send an HTTP PUT request for updating the staged rollout rate.
      try: response = requests.put(api_url, headers=headers, json=payload) print("Status Code:", response.status_code) data_shows = response.json() print("Parsed JSON:", json.dumps(data_shows, indent=4)) except Exception as e: print("Error:", str(e)) Response on Success
      A successful request returns the response “Ok”.
      Status Code: 200 Parsed JSON: { "resultCode": "0000", "resultMessage": "Ok", "data": {} } After a successful response, Seller Portal UI looks like this:

      Figure 2: Seller Portal UI after updating the staged rollout rate



      Implementing the “View Staged Rollout Binaries” Endpoint
      Before modifying which binaries participate in a staged rollout, you need to know the current state of the binary. This GET endpoint returns the list of binaries associated with a staged rollout for a given application, giving you the binarySeq values you need to take further action.
      Application Information
      To get application information, you only need the content ID and application status values.
      # Content ID and parameters contentId = '<Content ID of your app>' appStatus= 'REGISTRATION' Here, appStatus can be set as either “REGISTRATION” or “SALE”, depending on which version you want to inspect.
      API Endpoint
      Define the api_url value, including the content ID and application status values, to get the staged rollout binaries.
      # Defining the API endpoint (GET request) api_url=f"https://devapi.samsungapps.com/seller/v2/content/stagedRolloutBinary?contentId={Content_ID}&appStatus={appStatus}" GET Operation
      Send an HTTP GET request to the Galaxy Store Server with the api_url and headers values.
      try: response = requests.get(api_url, headers=headers) print("Status Code:", response.status_code) data_shows = response.json() print("Parsed JSON:", json.dumps(data_shows, indent=4)) except Exception as e: print("Error:", str(e)) Response on Success
      This is the success response, after completing the above operation.
      Status Code: 200 Parsed JSON: { "resultCode": "0000", "resultMessage": "Ok", "data": { "binaries": [ { "seq": 3, "versionCode": "7", "versionName": "1.1", "fileName": "App_20260202102640596.apk", "fileSize": "93.49", "rolloutStatus": "ENABLED", "appStatus": "REGISTRATION" } ] } } The response returns an array of binary objects, each containing the binarySeq identifier, version information, and whether the binary is currently included in the staged rollout. Keep a note of the binarySeq values, as you need them when calling the “Update the Staged Rollout Binary” endpoint.
      NoteIf you do not know the binarySeq for a binary, you can also retrieve it by calling GET /seller/contentInfo?contentId=XXXXXXXXXXXX, which returns full application details including all registered binaries and their sequence numbers. Implementing the “Update the Staged Rollout Binary” Endpoint
      This endpoint programmatically modifies the specific binary files associated with an active staged rollout, allowing developers to manage which version is being distributed. Using the API, the rollout status is set to either “ENABLED” or “DISABLED”, which refers to the “ADD” or “REMOVE” functions used to manage specific files within a release.
      ENABLED (ADD): This function attaches a specific binary sequence to your staged rollout, making it active for the designated percentage of users.
      DISABLED (REMOVE): This function disables a staged rollout immediately and makes that build available to all users globally.
      API Endpoint
      Define the API endpoint for changing the rollout status.
      # Defining the API endpoint (PUT request) api_url= "https://devapi.samsungapps.com/seller/v2/content/stagedRolloutBinary" Payload
      To change a specific application’s rollout binary, send its content ID, function value (“ADD” or “REMOVE”) and the binary sequence value inside a JSON payload.
      # Payload (ADD or REMOVE binary to staged rollout) payload = { "contentId": "<Content Id of your app>", "function": "REMOVE", # or ADD "binarySeq": "3" } This code removes the specific binary from the list. You can check this modification from the Seller Portal UI.

      Figure 3: Disabled staged rollout binary in the Seller Portal UI



      PUT Operation
      Send an HTTP PUT request to update the staged rollout binaries to the Galaxy Store Server.
      try: response = requests.put(api_url, headers=headers, json=payload) print("Status Code:", response.status_code) data_shows = response.json() print("Parsed JSON:", json.dumps(data_shows, indent=4)) except Exception as e: print("Error:", str(e)) Response on Success
      After a successful change of the rollout status from “ENABLE” to “DISABLE”, or vice versa, the operation returns a resultMessage with the value “Ok”.
      Status Code: 200 Parsed JSON: { "resultCode": "0000", "resultMessage": "Ok", "data": {} } Response on Error
      See the Failure response codes for a list of possible response codes when a request fails.
      Key Cautions and Limitations
      Samsung's official documentation makes several important constraints explicit that every seller needs to keep in mind:
      The staged rollout rate cannot decrease for live applications. Once you set a rollout rate for a SALE version, the only valid options are increasing the rate or disabling the rollout entirely. In an application, only one staged rollout can be active at a time. You must disable an existing rollout before enabling a new one. Concurrent rollouts on the same content ID are not supported. The rules for binary contentStatus are very strict. The “Update the Staged Rollout Binary” endpoint only works when the application has a status of “REGISTERING”, “UPDATING”, “RE_REGISTERING”, or “READY_FOR_SALE”. The “FOR_SALE" status is not supported for this operation. The “DISABLE_ROLLOUT” action is irreversible in terms of exposure. Disabling a staged rollout immediately makes the current build available to all users globally. You cannot "re-stage" that release. Application review is still required. A staged rollout is only a distribution control mechanism and does not bypass the standard Samsung Galaxy Store review process. Applications must pass review before any users receive the update. Manual publication adds an extra step. If publicationType is set to “manual", even after passing review, you must call POST /seller/contentStatusUpdate with contentStatus: "FOR_SALE" to release the pending application. New application registration is not supported through the API. The Galaxy Store Developer API only manages applications that have already been registered in Seller Portal. First-time application submissions must begin in the Seller Portal web interface. The HTTPS protocol is mandatory for all API calls. HTTP requests are rejected. Conclusion
      The Galaxy Store Developer API enables developers to manage application releases programmatically through staged rollouts. By integrating these APIs into your development workflow, you can improve release reliability, reduce manual effort, and enhance the overall user experience. Staged rollout management is essential for modern application delivery, empowering teams to scale effectively through automated and controlled release processes.
      If you have any questions about or need help with the information in this article, you can reach out to us on the Samsung Developers Forum or contact us through Developer Support.
      For additional reference you can check out the following resources:
      How to Create an Access Token for the Galaxy Store Developer API Using Python: Learn how to create an access token using the Galaxy Store Developer API and Python. Set a Staged Rollout in the Seller Portal: Learn how to configure a staged rollout of applications in Seller Portal. Python Sample Source Code: Learn how to install Python on your PC and the setup for implementing these APIs. View the full blog at its source
    • By Samsung Newsroom
      Samsung Wallet provides an e-wallet service to its customers through wallet cards. Adding a card to the user device is normally triggered by user interaction, cards are added to their device when the Add to Wallet button or link is pressed. The Adding Wallet Cards API provides the functionality to add cards to user devices directly without user interaction. A partner can provide wallet cards to the user’s wallet directly using the user’s email or mobile number.
      This article demonstrates a complete implementation of the Adding Wallet Cards API. In the example scenario, we add a Coupon type card to a user device from a partner’s server using this API without any user interaction.
      System requirements
      The Adding Wallet Cards API has the following prerequisites:
      New Samsung Wallet users must first complete the onboarding procedure and obtain the required security certificates. Create a new Coupon card template through the Wallet Partners Portal and launch the card. As a partner you can also create a card template through the partner server. For more details, refer to the Create Samsung Wallet Card Templates Using the Server API. Using the Adding Wallet Cards API requires explicit permission from Samsung. Contact Samsung Developer Support for authorization. API fundamentals
      This RESTful interface enables partners to deliver wallet cards directly to user accounts from their servers.
      Endpoint: The service URL where card addition requests are processed.
      https://tsapi-card.walletsvc.samsung.com/atw/v1/cards/{cardId} Headers: Only verified partners can utilize this API. Header information establishes secure communication between the partner and Samsung servers.
      Authorization: Bearer token authentication. Refer to JSON Web Token documentation for specifications. x-smcs-partner-id: Your unique partner identifier required for API access. x-request-id: A unique UUID string that identifies each request. Body: Must include a cdata parameter containing a JWT token with card details and user account information.
      Detailed API specifications are available in the official documentation.
      API implementation process
      The Adding Wallet Cards API enables partners to deliver cards directly to the user's account or wallet. Follow this step-by-step approach to implement the API. For a better understanding of the overall process, download the sample source code.
      Step 1: Cryptographic key management
      Extract necessary keys from security certificates for JWT token generation in subsequent steps.
      Public key retrieval
      The following function extracts public keys from partner.crt and samsung.crt certificate files received during the onboarding process.
      def getPublicKey(crt_path): """ Extract public key from a .crt file. """ try: with open(crt_path, "rb") as f: crt_data = f.read() certificate = x509.load_pem_x509_certificate(crt_data, default_backend()) public_key = certificate.public_key() public_key_pem = public_key.public_bytes( encoding=serialization.Encoding.PEM, format=serialization.PublicFormat.SubjectPublicKeyInfo ) return public_key_pem except Exception as error: print(f"Error reading public key from {crt_path}: {error}") return None Private key retrieval
      This function retrieves the private key from the .pem file generated during the onboarding process.
      def getPrivateKey(pem_path): ''' Extract private key from a .pem file. ''' try: with open(pem_path, "rb") as data: private_key = serialization.load_pem_private_key( data.read(), password=None, backend=default_backend() ) return private_key except Exception as error: print(f"Error reading private key from {pem_path}: {error}") return None Step 2: Authentication token creation
      Samsung validates each API request through an authorization token in JWT format. To generate a valid authentication token:
      Construct an authHeader with AUTH as the payload content type. Include the certificate ID from My account > Encryption Management in the Wallet Partners Portal. Build the payload using the authHeader structure. Generate the final authorization token. The following code snippet implements the steps above.
      def generateAuthToken(partnerId, certificateId, utcTimestamp, privateKey, cardId): auth_header = { "cty": "AUTH", "ver": 3, "certificateId": certificateId, "partnerId": partnerId, "utc": utcTimestamp, "alg": "RS256" } auth_payload = { "API": { "method": "POST", "path": f"/atw/v1/cards/{cardId}" }, } auth_token = jwt.encode( payload=auth_payload, key=privateKey, algorithm='RS256', headers=auth_header ) return auth_token Step 3: Card data token generation (cdata)
      The request payload requires a cdata parameter containing a JWT token with card information and user details. Follow these steps to construct the cdata token.
      Card information structure
      Build a card data object containing all necessary information about the card to be delivered and the target user account.
      cDataPayload = { "card": { "type": "coupon", "subType": "others", "data": [{ "refId": "e389dc8a-4616-494c-a8b3-80380f449fc2", "createdAt": 1727913600000, "updatedAt": 1727913600000, "language": "ko", "attributes": { "title": "Strawberry Icecream-1", "orderId": "order-001", "groupingId": "grouping-001", "mainImg": "https://djcpagh05u38x.cloudfront.net/wlt/kr/stg/IHGhULmHRiqfhI73YdQZcA/LDZf4FWLQ9i5iqoym1R2yw.png", "brandName": "Cioud Icecream", "expiry": 1762225720029, "issueDate": 1727913600000, "redeemDate": 1727913600489, "noticeDesc": "<div>▶Precautions<br>-This product is an example image and may be different from the actual product. <br>-Only available within the expiration date.<br><br>", "editableYn": "N", "deletableYn": "Y", "displayRedeemButtonYn": "N", "addToWalletCouponYn": "Y", "notificationYn": "Y", "appLinkLogo": "https://play-lh.googleusercontent.com/O5iWMHHBRmiGA_4XDsXMiZThLd-wwu2ln6FBz6zNPdlmKif0i98sfHtWZkYzjan-Tw=w240-h480-rw", "appLinkName": "Cioud Icecream", "appLinkData": "https://www.samsung.com/us", "barcode.value": "1111222233334444", "barcode.serialType": "BARCODE", "barcode.ptFormat": "BARCODESERIAL", "barcode.ptSubFormat": "CODE128" }, }] }, "account": { "type": "email", "value": "[email protected]" } } Cdata JWT token construction
      Generate the JWT token using the following implementation. Additional information about the JWT format is available in the Card Data Token section of the Security documentation.
      def generateCDataToken(partnerId, samsungPublicKey, partnerPrivateKey, certificateId, utcTimestamp, data): jwe_header = { "alg": "RSA1_5", "enc": "A128GCM" } jwe_token = jwe.encrypt( data, samsungPublicKey, encryption=jwe_header["enc"], algorithm=jwe_header["alg"] ) print(f"jwe_token: \n{jwe_token}\n") jws_header = { "alg": "RS256", "cty": "CARD", "ver": 3, "certificateId": certificateId, "partnerId": partnerId, "utc": utcTimestamp, } jws_token = jws.sign( jwe_token, key=partnerPrivateKey, algorithm='RS256', headers=jws_header ) print(f"jws_token: \n{jws_token}\n") return jws_token Step 4: Build HTTP request and execute
      With all required components prepared, construct the card addition HTTP request using the following code structure:
      # --- Prepare JSON body (Python dictionary) --- c_data_json_body = { "cdata": cDataToken } # --- Build HTTP Request --- headers = { "Authorization": "Bearer " + authToken, "x-smcs-partner-id": partnerId, "x-request-id": requestId, "x-request-cc2": "KR", "Content-Type": "application/json" } # --- Execute HTTP Request --- try: response = requests.post(endpoint, json=c_data_json_body, headers=headers) response.raise_for_status() print("Wallet Card Added successfully: " + json.dumps(response.json())) except requests.exceptions.RequestException as e: print("Failed to add Wallet Card:") print(f"Error: {e}") if response: print("Response body:", response.text) Running the application
      Once the four steps described above are implemented, open the sample project and do the following:
      Update the partner id, certificate id, and card id values in src/main.py with your actual credentials. Replace the partner.crt, samsung.crt and private_key.pem files with your credential files in the /cert directory. Install all dependencies listed in the requirements.txt file using command pip install -r requirements.txt. Run the main script using the command python src/main.py in the terminal. After successful execution of the requests, you will get a Success message. Get the full response code in the Response section of the documentation. A push notification is sent to the user’s device to confirm the successful card registration. Once this is done, open your Samsung wallet and navigate to the coupon card list and you will find the card there.
      Conclusion
      Now that you have familiarized yourself with the process of adding cards to the user device using the Adding Wallet Cards API, you can implement this logic to your server and use it to improve your card management.
      Additional resources
      For more information on this topic, consult the following resources.
      Complete source code Create Samsung Wallet Card Templates Using the Server API Official Samsung Wallet API documentation View the full blog at its source
    • By Samsung Newsroom
      In a previous blog article, we learned how we could utilize Samsung Wallet's RP SDK in order to verify a user's identity from an Android application. In this tutorial, we learn how to verify a user's identity directly from a website using Samsung Wallet and its Web2App API in a Spring Boot web server.
      Prerequisites
      The process described has the following prerequisites:
      A valid US driver's license or state ID for the user whose identity is to be verified The Samsung Galaxy device used needs to be registered for the US region and have mDL support Complete the Samsung Wallet Partner onboarding process Create a Wallet Card template with the Relying Party type in the Samsung Wallet Partners Portal Implementing the Verify with Wallet functionality in your website
      The Verify with Wallet (VWW) process utilizing the Web2App method consists of two distinct parts.
      The "Verify with Samsung Wallet" button. This button contains the VWW link with the RP card data tokenized as the CData. The user can click this VWW link to initiate the verification process. The partner server containing the /key and /auth endpoints. The partner server processes the requests sent from the Samsung Wallet application and handles the complete VWW process. Frontend configuration
      In order to initiate the Verify with Wallet process, we need to implement a "Verify with Samsung Wallet" button in a webpage.
      Implementing the button is a very simple process similar to creating a traditional "Add to Wallet" button. We can make use of the data transmit link approach and create a button that contains the VWW link: https://a.swallet.link/vww/v1/{cardId}#Clip?cdata={cdata}
      Replace {cardId} with the ID of your own card. Meanwhile, the CData value needs to be generated in real time. This is done using a process similar to generating CData for ATW operation, only with the payload contained being different according to the specification for the Relying Party card type. Check out the sample code for the complete process of CData generation and using it in the button.
      Backend configuration
      Once the button implementation is complete, you need to configure your server to handle the exchange of information between your server and Samsung Wallet application. The VWW process requires the partner to define 2 API endpoints:
      /rp/v1.0/{cardId}/{refId}/key: Establishes a secure session and prepares the request data for the process. /rp/v1.0/{cardId}/{refId}/auth: Processes encrypted authentication data and mDL data received from the Wallet application. The workflow for the information exchange is as follows:
      Once the VWW button is clicked, the Samsung Wallet application opens. Samsung Wallet checks if the device has a driver's license already enrolled in the device. If an mDL already exists on the device, the Samsung Wallet application calls the /key endpoint to establish a session. After establishing session with the partner server and retrieving the mDoc request, the Samsung Wallet application prompts the user to confirm if they wish to share their information with the partner. After the user confirms that they wish to proceed, the application finally sends the requested information to the /auth API to complete the VWW process. Define the /key endpoint
      When the user clicks the "Verify with Samsung Wallet" button, the Samsung Wallet application first checks if a driver's license is enrolled. If a license is found, the application generates "device engagement bytes" in accordance with the ISO-18013-5 specification. These bytes are then transmitted to the server's /key API endpoint to establish a verification session.
      The POST request body is JSON with a single field called data. This field value is the JWT containing encrypted device engagement bytes.
      {"data": "………"} In the /key API endpoint,
      Accept the POST request sent to the path /{cardId}/{refId}/key Extract the data field from the body as the JWT and decrypt it to receive the device engagement bytes. Establish a session using the device engagement bytes. Create the mDoc request data and send it back to the Samsung Wallet application as response to the POST request. The complete process is shown below:
      @PostMapping("{cardId}/{refId}/key") fun receiveKey( @PathVariable cardId: String, @PathVariable refId: String, @RequestBody body: String ): ResponseEntity<String> { val cData = JsonParser.parseString(body).asJsonObject.get("data").toString() val base64EngagementBytes = JwtGen.decryptBase64Engagement(cData) val mDoc18013 = createMDoc10813(base64EngagementBytes) val cdataResponse = "{\"data\": \"${JwtGen.generateRequestJwt(mDoc18013)}\"}" return ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).body(cdataResponse) } Decrypt the device engagement bytes from the request body
      The data field value received in the /key API contains the required device engagement bytes encoded in the JWT format. Simply decrypt the JWT in order to retrieve the device engagement bytes. Here the decryptBase64Engagement() function is defined as follows:
      fun decryptBase64Engagement(data: String): ByteArray { val signedJWT: SignedJWT = SignedJWT.parse(data) val payload = signedJWT.payload val jwe = JWEObject.parse(payload.toString()) val partnerPrivateKey = KeyUtil.readPrivateKey(PARTNER_PRIVATE_KEY) val decrypter = RSADecrypter(partnerPrivateKey) jwe.decrypt(decrypter) val base64Engagement = jwe.payload.toJSONObject().get("data").toString() val base64EngagementBytes = Base64.getUrlDecoder().decode(base64Engagement) return base64EngagementBytes } Simply perform the JWT decryption operation using your private key to get the decrypted JWE payload in the JSON format. In the JSON-formatted payload, the data field contains the device engagement bytes encoded in the base64URL string format. Decode the string using a base64URL decoder and you get the final device engagement bytes.
      Create a shared session using device engagement bytes
      The createMDoc10813(base64EngagementBytes) function creates a shared session between the /key API and /auth API using a companion object. Having a shared session between the two endpoints is mandatory in order to decrypt the information provided by the Samsung Wallet application later on.
      Inside the companion object, we also need to generate an elliptic curve keypair in order to establish the encrypted session. The companion object is defined as shown below:
      companion object{ val keyPair = KeyUtil.generateEcKeyPair() var mDoc18013: Mdoc18013? = null fun createMDoc10813(base64EngagementBytes: ByteArray): Mdoc18013 { if (mDoc18013 == null ) { mDoc18013 = Mdoc18013(keyPair, base64EngagementBytes ) return mDoc18013!! } else{ return mDoc18013!! } } fun getMDoc10813(): Mdoc18013 { return mDoc18013!! } } The elliptic curve keypair is generated using a simple KeyPairGenerator class instance.
      fun generateEcKeyPair(): KeyPair { val keyPairGenerator = KeyPairGenerator.getInstance("EC") val ecGenParameterSpec = ECGenParameterSpec("secp256r1") keyPairGenerator.initialize(ecGenParameterSpec) return keyPairGenerator.generateKeyPair() } Prepare the mDoc request data
      Preparing the mDoc request data is the most crucial part of the VWW operation. The request data defines the data that needs to be retrieved from mDL. The generateRequestJwt() function can be divided into several parts:
      Define and encode the request data payload. Encrypt the device request. Create session establishment data using the encrypted device request bytes. Create a signed JWT. Below, we go through these steps one at a time.
      Define the request data payload and encode it to a CBOR Byte Array
      // Define requested data fields val requestData = """ { "docType": "org.iso.18013.5.1.mDL", "nameSpaces": { "org.iso.18013.5.1": { "family_name": true, "age_in_years": true, "issue_date": true, "expiry_date": true, "document_number": false, "issuing_authority": false }, "org.iso.18013.5.1.aamva": { "DHS_compliance": false } } } """.trimIndent() // CBOR encoding process with tagging val firstEncoded = CBORObject.FromJSONString(requestData).EncodeToBytes() val thirdEncoded = CBORObject.FromObjectAndTag(firstEncoded, 24).EncodeToBytes() val itemRequestBytesList = listOf(thirdEncoded) // Create mDoc items requests array val docRequestsArray = CBORObject.NewArray() itemRequestBytesList.forEach { val docRequest = CBORObject.NewMap() docRequest.set("itemsRequest", CBORObject.DecodeFromBytes(it)) docRequestsArray.Add(docRequest) } // Create device request using docRequestArray val deviceRequest = CBORObject.NewMap() deviceRequest.set("version", CBORObject.FromObject("1.0")) deviceRequest.set("docRequests", docRequestsArray) Encrypt the device request
      val encryptedDeviceRequestBytes = mDoc18013.encryptDeviceRequest(deviceRequest.EncodeToBytes()) Create session establishment data using the encrypted device request bytes
      val establishment = CBORObject.NewMap() establishment.set("eReaderKey", CBORObject.FromObjectAndTag(mDoc18013.getEReaderKey(),24)) establishment.set("data", CBORObject.FromObject(encryptedDeviceRequestBytes)) val establishmentString = Base64.getUrlEncoder().encodeToString(establishment.EncodeToBytes()) Create a signed JWT using the establishmentString as the JWE payload
      val jweObj = JWEObject(JWEHeader.Builder(JWEAlgorithm.RSA_OAEP_256, EncryptionMethod.A128GCM).build(), Payload(establishmentString)) val encryptor = RSAEncrypter(samsungPublicKey as RSAPublicKey) jweObj.encrypt(encryptor) val jwsHeader = JWSHeader.Builder(JWSAlgorithm.RS256) .contentType("AUTH") .customParam("partnerId", "412255212345678910") .customParam("certificateId", "A123") .customParam("ver", "3") .customParam("utc", System.currentTimeMillis()) .build() val jwsObj = JWSObject(jwsHeader, Payload(jweObj.serialize())) val rsaJwk = RSAKey.Builder(partnerPublicKey as RSAPublicKey).privateKey(partnerPrivateKey).build() val jwsSigner = RSASSASigner(rsaJwk) jwsObj.sign(jwsSigner) return jwsObj.serialize() Now, we can send this JWT back as the response from the /key API.
      If everything is done properly, the Samsung Wallet application should receive the verification request along with the list of requested fields. After processing and verifying the request, the Samsung Wallet application needs to prompt the user to verify their identity. Once the user verifies their identity using the application, it sends the requested information back to the /auth API endpoint.
      Next, let's define the /auth API endpoint to retrieve the requested information.
      Define the /auth API endpoint
      Similar to the previously defined /key API endpoint, the /auth API endpoint also receives a single JSON payload with a single field called data, which contains the requested information in a JWT encoded format.
      {"data": "………"} Decrypt the JWT payload from the request body
      We can extract the data field and decrypt the JWT following the same process used in the /key API.
      @PostMapping("{cardId}/{refId}/auth") fun receiveAuth( @PathVariable cardId: String, @PathVariable refId: String, @RequestBody body: String ): HttpStatus { val responseData = JsonParser.parseString(body).asJsonObject.get("data").toString() val signedJWT: SignedJWT = SignedJWT.parse(responseData) val payload = signedJWT.payload val jwe = JWEObject.parse(payload.toString()) val partnerPrivateKey = JwtGen.partnerPrivateKey val decrypter = RSADecrypter(partnerPrivateKey) jwe.decrypt(decrypter) // Process and decrypt the data until the requested information is retrieved return HttpStatus.OK } After the decryption operation, we get another JSON object in the decrypted JWE payload. In this JSON payload, the data field contains the encoded data of the information we requested. To decode and decrypt this data:
      Decode the extracted data field value using Base64URL decoder. This gives us the encrypted mDoc response in a CBOR byte array. Decode the CBOR object from the byte array and get the mDoc data from the data field. Decrypt the mDoc data using the mDoc18013.decryptMdocResponse() function to retrieve the plain response in the JSON format. WarningThe mDoc18013 instance used for this step must be the same instance used in the /key API. Otherwise, the decryption operation fails. val mDoc18013 = getMDoc10813() val cborData = jwe.payload.toJSONObject().get("data").toString() val decodedData = Base64.getUrlDecoder().decode(cborData) val mDocResponse = CBORObject.DecodeFromBytes(decodedData) val mDocData = mDocResponse.get("data") val decryptMdocResponseBytes = mDoc18013.decryptMdocResponse(mDocData.GetByteString()) val plainResponse = CBORObject.DecodeFromBytes(decryptMdocResponseBytes).ToJSONString() After these steps, we finally have the mDoc response in a plain JSON format.
      { "status": 0, "version": "1.0", "documents": [ { "docType": "org.iso.18013.5.1.mDL", "deviceSigned": {}, "issuerSigned": { "issuerAuth": ["......."], "nameSpaces": { "org.iso.18013.5.1": [ "pGhkaWdlc3RJRBkhfWZyYW5kb21Uczc4ZnY4c2NoNGMyZHR5MnlyOTZxZWxlbWVudElkZW50aWZpZXJsYWdlX2luX3llYXJzbGVsZW1lbnRWYWx1ZRgs", "pGhkaWdlc3………" ], "org.iso.18013.5.1.aamva": [ "pGhkaWdlc3RJRBlLD2ZyYW5kb21Uczh5cmptbTU4OHMyNzY4emozNm5xZWxlbWVudElkZW50aWZpZXJuREhTX2NvbXBsaWFuY2VsZWxlbWVudFZhbHVlYUY" ] } } } ] } Here, the values inside the org.iso.18013.5.1 and org.iso.18013.5.1.aamva are the fields we initially requested in the Key API. Simply decode these CBOR-encoded fields to retrieve the information you requested. For example, the "pGhkaWdlc3RJRBkhfWZyYW5kb21Uczc4ZnY4c2NoNGMyZHR5MnlyOTZxZWxlbWVudElkZW50aWZpZXJsYWdlX2luX3llYXJzbGVsZW1lbnRWYWx1ZRgs" value informs us that element name is age_in_years and its value is "44," meaning the subject is 44 years old. We can extract the rest of the requested information by decoding the other provided values in the same way.
      Figure 1: Verifying user identity using VWW Web2App process
      Summary
      In this tutorial, we learned how we can implement user identity verification on a website utilizing Samsung Wallet's Verify with Wallet functionality. By making use of the Web2App method discussed in this article, you can allow users to securely confirm and verify their digital identity using their mobile driver's licenses.
      Related resources
      ISO/IEC 18013-5:2021 - Personal identification — ISO-compliant driving licence — Part 5: Mobile driving licence (mDL) application Mobile Driver License - American Association of Motor Vehicle Administrators - AAMVA Verify with Wallet API Guidelines Relying Party Card Specifications Sample Code Download Link View the full blog at its source
    • Government UFO Files
    • By Samsung Newsroom
      In a previous blog article, we learned how we could utilize Samsung Wallet's RP SDK in order to verify a user's identity from an Android application. In this tutorial, we learn how to verify a user's identity directly from a website using Samsung Wallet and its Web2App API in a Spring Boot web server.
      Prerequisites
      The process described has the following prerequisites:
      A valid US driver's license or state ID for the user whose identity is to be verified The Samsung Galaxy device used needs to be registered for the US region and have mDL support Complete the Samsung Wallet Partner onboarding process Create a Wallet Card template with the Relying Party type in the Samsung Wallet Partners Portal Implementing the Verify with Wallet functionality in your website
      The Verify with Wallet (VWW) process utilizing the Web2App method consists of two distinct parts.
      The "Verify with Samsung Wallet" button. This button contains the VWW link with the RP card data tokenized as the CData. The user can click this VWW link to initiate the verification process. The partner server containing the /key and /auth endpoints. The partner server processes the requests sent from the Samsung Wallet application and handles the complete VWW process. Frontend configuration
      In order to initiate the Verify with Wallet process, we need to implement a "Verify with Samsung Wallet" button in a webpage.
      Implementing the button is a very simple process similar to creating a traditional "Add to Wallet" button. We can make use of the data transmit link approach and create a button that contains the VWW link: https://a.swallet.link/vww/v1/{cardId}#Clip?cdata={cdata}
      Replace {cardId} with the ID of your own card. Meanwhile, the CData value needs to be generated in real time. This is done using a process similar to generating CData for ATW operation, only with the payload contained being different according to the specification for the Relying Party card type. Check out the sample code for the complete process of CData generation and using it in the button.
      Backend configuration
      Once the button implementation is complete, you need to configure your server to handle the exchange of information between your server and Samsung Wallet application. The VWW process requires the partner to define 2 API endpoints:
      /rp/v1.0/{cardId}/{refId}/key: Establishes a secure session and prepares the request data for the process. /rp/v1.0/{cardId}/{refId}/auth: Processes encrypted authentication data and mDL data received from the Wallet application. The workflow for the information exchange is as follows:
      Once the VWW button is clicked, the Samsung Wallet application opens. Samsung Wallet checks if the device has a driver's license already enrolled in the device. If an mDL already exists on the device, the Samsung Wallet application calls the /key endpoint to establish a session. After establishing session with the partner server and retrieving the mDoc request, the Samsung Wallet application prompts the user to confirm if they wish to share their information with the partner. After the user confirms that they wish to proceed, the application finally sends the requested information to the /auth API to complete the VWW process. Define the /key endpoint
      When the user clicks the "Verify with Samsung Wallet" button, the Samsung Wallet application first checks if a driver's license is enrolled. If a license is found, the application generates "device engagement bytes" in accordance with the ISO-18013-5 specification. These bytes are then transmitted to the server's /key API endpoint to establish a verification session.
      The POST request body is JSON with a single field called data. This field value is the JWT containing encrypted device engagement bytes.
      {"data": "………"} In the /key API endpoint,
      Accept the POST request sent to the path /{cardId}/{refId}/key Extract the data field from the body as the JWT and decrypt it to receive the device engagement bytes. Establish a session using the device engagement bytes. Create the mDoc request data and send it back to the Samsung Wallet application as response to the POST request. The complete process is shown below:
      @PostMapping("{cardId}/{refId}/key") fun receiveKey( @PathVariable cardId: String, @PathVariable refId: String, @RequestBody body: String ): ResponseEntity<String> { val cData = JsonParser.parseString(body).asJsonObject.get("data").toString() val base64EngagementBytes = JwtGen.decryptBase64Engagement(cData) val mDoc18013 = createMDoc10813(base64EngagementBytes) val cdataResponse = "{\"data\": \"${JwtGen.generateRequestJwt(mDoc18013)}\"}" return ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).body(cdataResponse) } Decrypt the device engagement bytes from the request body
      The data field value received in the /key API contains the required device engagement bytes encoded in the JWT format. Simply decrypt the JWT in order to retrieve the device engagement bytes. Here the decryptBase64Engagement() function is defined as follows:
      fun decryptBase64Engagement(data: String): ByteArray { val signedJWT: SignedJWT = SignedJWT.parse(data) val payload = signedJWT.payload val jwe = JWEObject.parse(payload.toString()) val partnerPrivateKey = KeyUtil.readPrivateKey(PARTNER_PRIVATE_KEY) val decrypter = RSADecrypter(partnerPrivateKey) jwe.decrypt(decrypter) val base64Engagement = jwe.payload.toJSONObject().get("data").toString() val base64EngagementBytes = Base64.getUrlDecoder().decode(base64Engagement) return base64EngagementBytes } Simply perform the JWT decryption operation using your private key to get the decrypted JWE payload in the JSON format. In the JSON-formatted payload, the data field contains the device engagement bytes encoded in the base64URL string format. Decode the string using a base64URL decoder and you get the final device engagement bytes.
      Create a shared session using device engagement bytes
      The createMDoc10813(base64EngagementBytes) function creates a shared session between the /key API and /auth API using a companion object. Having a shared session between the two endpoints is mandatory in order to decrypt the information provided by the Samsung Wallet application later on.
      Inside the companion object, we also need to generate an elliptic curve keypair in order to establish the encrypted session. The companion object is defined as shown below:
      companion object{ val keyPair = KeyUtil.generateEcKeyPair() var mDoc18013: Mdoc18013? = null fun createMDoc10813(base64EngagementBytes: ByteArray): Mdoc18013 { if (mDoc18013 == null ) { mDoc18013 = Mdoc18013(keyPair, base64EngagementBytes ) return mDoc18013!! } else{ return mDoc18013!! } } fun getMDoc10813(): Mdoc18013 { return mDoc18013!! } } The elliptic curve keypair is generated using a simple KeyPairGenerator class instance.
      fun generateEcKeyPair(): KeyPair { val keyPairGenerator = KeyPairGenerator.getInstance("EC") val ecGenParameterSpec = ECGenParameterSpec("secp256r1") keyPairGenerator.initialize(ecGenParameterSpec) return keyPairGenerator.generateKeyPair() } Prepare the mDoc request data
      Preparing the mDoc request data is the most crucial part of the VWW operation. The request data defines the data that needs to be retrieved from mDL. The generateRequestJwt() function can be divided into several parts:
      Define and encode the request data payload. Encrypt the device request. Create session establishment data using the encrypted device request bytes. Create a signed JWT. Below, we go through these steps one at a time.
      Define the request data payload and encode it to a CBOR Byte Array
      // Define requested data fields val requestData = """ { "docType": "org.iso.18013.5.1.mDL", "nameSpaces": { "org.iso.18013.5.1": { "family_name": true, "age_in_years": true, "issue_date": true, "expiry_date": true, "document_number": false, "issuing_authority": false }, "org.iso.18013.5.1.aamva": { "DHS_compliance": false } } } """.trimIndent() // CBOR encoding process with tagging val firstEncoded = CBORObject.FromJSONString(requestData).EncodeToBytes() val thirdEncoded = CBORObject.FromObjectAndTag(firstEncoded, 24).EncodeToBytes() val itemRequestBytesList = listOf(thirdEncoded) // Create mDoc items requests array val docRequestsArray = CBORObject.NewArray() itemRequestBytesList.forEach { val docRequest = CBORObject.NewMap() docRequest.set("itemsRequest", CBORObject.DecodeFromBytes(it)) docRequestsArray.Add(docRequest) } // Create device request using docRequestArray val deviceRequest = CBORObject.NewMap() deviceRequest.set("version", CBORObject.FromObject("1.0")) deviceRequest.set("docRequests", docRequestsArray) Encrypt the device request
      val encryptedDeviceRequestBytes = mDoc18013.encryptDeviceRequest(deviceRequest.EncodeToBytes()) Create session establishment data using the encrypted device request bytes
      val establishment = CBORObject.NewMap() establishment.set("eReaderKey", CBORObject.FromObjectAndTag(mDoc18013.getEReaderKey(),24)) establishment.set("data", CBORObject.FromObject(encryptedDeviceRequestBytes)) val establishmentString = Base64.getUrlEncoder().encodeToString(establishment.EncodeToBytes()) Create a signed JWT using the establishmentString as the JWE payload
      val jweObj = JWEObject(JWEHeader.Builder(JWEAlgorithm.RSA_OAEP_256, EncryptionMethod.A128GCM).build(), Payload(establishmentString)) val encryptor = RSAEncrypter(samsungPublicKey as RSAPublicKey) jweObj.encrypt(encryptor) val jwsHeader = JWSHeader.Builder(JWSAlgorithm.RS256) .contentType("AUTH") .customParam("partnerId", "412255212345678910") .customParam("certificateId", "A123") .customParam("ver", "3") .customParam("utc", System.currentTimeMillis()) .build() val jwsObj = JWSObject(jwsHeader, Payload(jweObj.serialize())) val rsaJwk = RSAKey.Builder(partnerPublicKey as RSAPublicKey).privateKey(partnerPrivateKey).build() val jwsSigner = RSASSASigner(rsaJwk) jwsObj.sign(jwsSigner) return jwsObj.serialize() Now, we can send this JWT back as the response from the /key API.
      If everything is done properly, the Samsung Wallet application should receive the verification request along with the list of requested fields. After processing and verifying the request, the Samsung Wallet application needs to prompt the user to verify their identity. Once the user verifies their identity using the application, it sends the requested information back to the /auth API endpoint.
      Next, let's define the /auth API endpoint to retrieve the requested information.
      Define the /auth API endpoint
      Similar to the previously defined /key API endpoint, the /auth API endpoint also receives a single JSON payload with a single field called data, which contains the requested information in a JWT encoded format.
      {"data": "………"} Decrypt the JWT payload from the request body
      We can extract the data field and decrypt the JWT following the same process used in the /key API.
      @PostMapping("{cardId}/{refId}/auth") fun receiveAuth( @PathVariable cardId: String, @PathVariable refId: String, @RequestBody body: String ): HttpStatus { val responseData = JsonParser.parseString(body).asJsonObject.get("data").toString() val signedJWT: SignedJWT = SignedJWT.parse(responseData) val payload = signedJWT.payload val jwe = JWEObject.parse(payload.toString()) val partnerPrivateKey = JwtGen.partnerPrivateKey val decrypter = RSADecrypter(partnerPrivateKey) jwe.decrypt(decrypter) // Process and decrypt the data until the requested information is retrieved return HttpStatus.OK } After the decryption operation, we get another JSON object in the decrypted JWE payload. In this JSON payload, the data field contains the encoded data of the information we requested. To decode and decrypt this data:
      Decode the extracted data field value using Base64URL decoder. This gives us the encrypted mDoc response in a CBOR byte array. Decode the CBOR object from the byte array and get the mDoc data from the data field. Decrypt the mDoc data using the mDoc18013.decryptMdocResponse() function to retrieve the plain response in the JSON format. WarningThe mDoc18013 instance used for this step must be the same instance used in the /key API. Otherwise, the decryption operation fails. val mDoc18013 = getMDoc10813() val cborData = jwe.payload.toJSONObject().get("data").toString() val decodedData = Base64.getUrlDecoder().decode(cborData) val mDocResponse = CBORObject.DecodeFromBytes(decodedData) val mDocData = mDocResponse.get("data") val decryptMdocResponseBytes = mDoc18013.decryptMdocResponse(mDocData.GetByteString()) val plainResponse = CBORObject.DecodeFromBytes(decryptMdocResponseBytes).ToJSONString() After these steps, we finally have the mDoc response in a plain JSON format.
      { "status": 0, "version": "1.0", "documents": [ { "docType": "org.iso.18013.5.1.mDL", "deviceSigned": {}, "issuerSigned": { "issuerAuth": ["......."], "nameSpaces": { "org.iso.18013.5.1": [ "pGhkaWdlc3RJRBkhfWZyYW5kb21Uczc4ZnY4c2NoNGMyZHR5MnlyOTZxZWxlbWVudElkZW50aWZpZXJsYWdlX2luX3llYXJzbGVsZW1lbnRWYWx1ZRgs", "pGhkaWdlc3………" ], "org.iso.18013.5.1.aamva": [ "pGhkaWdlc3RJRBlLD2ZyYW5kb21Uczh5cmptbTU4OHMyNzY4emozNm5xZWxlbWVudElkZW50aWZpZXJuREhTX2NvbXBsaWFuY2VsZWxlbWVudFZhbHVlYUY" ] } } } ] } Here, the values inside the org.iso.18013.5.1 and org.iso.18013.5.1.aamva are the fields we initially requested in the Key API. Simply decode these CBOR-encoded fields to retrieve the information you requested. For example, the "pGhkaWdlc3RJRBkhfWZyYW5kb21Uczc4ZnY4c2NoNGMyZHR5MnlyOTZxZWxlbWVudElkZW50aWZpZXJsYWdlX2luX3llYXJzbGVsZW1lbnRWYWx1ZRgs" value informs us that element name is age_in_years and its value is "44," meaning the subject is 44 years old. We can extract the rest of the requested information by decoding the other provided values in the same way.
      Figure 1: Verifying user identity using VWW Web2App process
      Summary
      In this tutorial, we learned how we can implement user identity verification on a website utilizing Samsung Wallet's Verify with Wallet functionality. By making use of the Web2App method discussed in this article, you can allow users to securely confirm and verify their digital identity using their mobile driver's licenses.
      Related resources
      ISO/IEC 18013-5:2021 - Personal identification — ISO-compliant driving licence — Part 5: Mobile driving licence (mDL) application Mobile Driver License - American Association of Motor Vehicle Administrators - AAMVA Verify with Wallet API Guidelines Relying Party Card Specifications Sample Code Download Link View the full blog at its source




×
×
  • Create New...