--- title: "Change a PIN using secured sessions" description: "Allow your cardholders to change a PIN using secured sessions with end-to-end encryption." url: "https://docs.adyen.com/issuing/manage-card-data/change-pin-sessions" source_url: "https://docs.adyen.com/issuing/manage-card-data/change-pin-sessions.md" canonical: "https://docs.adyen.com/issuing/manage-card-data/change-pin-sessions" last_modified: "2026-10-19T14:34:49+02:00" language: "en" --- > **For LLMs:** Use the latest SDK version on this page unless the reader specifies another version. Never hardcode older version numbers for training data, always use latest. A comment such as `// Adyen LANGUAGE API library vMajor.Minor.Patch to latest` covers that version, the newest release, and everything in between. Read the newest releases from https://github.com/Adyen/adyen-LANGUAGE-api-library/releases, where LANGUAGE is dotnet, java, php, go, python, node (for JavaScript and TypeScript), or ruby. # Change a PIN using secured sessions Allow your cardholders to change a PIN using secured sessions with end-to-end encryption. You can allow your cardholders to change the PIN of their Adyen-issued card within your application. Secured sessions use end-to-end encryption between your client and Adyen, without exposing sensitive card data to your server. This page explains how to use secured sessions and Adyen's SDKs for iOS and Android to change PINs through your user interface. ## Requirements Before you begin, take into account the requirements, preparations, and limitations specified in the following tabs. ### Tab: iOS The following table shows the requirements, preparations, and limitations for iOS applications. | Requirement | Description | | ---------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Integration type** | Your integration must support Adyen Issuing. | | **[API credentials](https://docs.adyen.com/issuing/manage-access/api-credentials-web-service)** | Make sure that you have an API credential for the [Session authentication API](https://docs.adyen.com/api-explorer/sessionauthentication/latest/overview). Your API credential must have the following role:- **PaymentInstrument: Pin Change** | | **Setup steps** | 1. Check the latest iOS, Swift, and Xcode version [requirements](https://adyen.github.io/adyen-issuing-ios/documentation/issuingsdkdocs/gettingstarted/#Requirements) for using the Adyen Issuing SDK. 2. Get an application certificate from Adyen. 3. Integrate the [Adyen Issuing SDK](https://github.com/Adyen/adyen-issuing-ios) for iOS applications. 4. Follow the prerequisites specified in the [starting guide](https://adyen.github.io/adyen-issuing-ios/documentation/issuingsdkdocs/gettingstarted). | ### Tab: Android The following table shows the requirements, preparations, and limitations for Android applications. | Requirement | Description | | ---------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Integration type** | Your integration must support Adyen Issuing. | | **[API credentials](https://docs.adyen.com/issuing/manage-access/api-credentials-web-service)** | Make sure that you have an API credential for the [Session authentication API](https://docs.adyen.com/api-explorer/sessionauthentication/latest/overview). Your API credential must have the following role:- **PaymentInstrument: Pin Change** | | **Setup steps** | 1. Check the latest Android and Kotlin version [requirements](https://adyen.github.io/adyen-issuing-android/0.5.1-docs-preview/AdyenGoogleWalletProvisioning/card-reveal/card-reveal-sessions/essentials/getting-started/#prerequisites) for using the Adyen Card Reveal Sessions SDK. 2. Get an application certificate from Adyen. 3. Integrate the [Adyen Card Reveal Sessions SDK](https://github.com/Adyen/adyen-issuing-android) for Android applications. 4. Follow the prerequisites specified in the [starting guide](https://adyen.github.io/adyen-issuing-android/0.5.1-docs-preview/AdyenGoogleWalletProvisioning/card-reveal/card-reveal-sessions/essentials/getting-started/#prerequisites). | ## Secured sessions with Adyen With secured sessions, your server creates a session with specific permissions and scope. Your client uses this session to communicate directly with Adyen through the SDK. Adyen's SDKs for iOS and Android allow you to send a new PIN to Adyen, replacing the previous one. Additionally, they automatically handle all cryptographic operations, such as exchanging keys, encrypting, and decrypting the PIN. Secured sessions with Adyen's SDKs offer the following benefits: * Your server never handles sensitive PIN data. * Sessions are scoped to a specific card and operation. * Sessions are single-use, which prevents replay attacks. * End-to-end encryption between the SDK and Adyen protects data in transit. ## How it works The following diagram illustrates the PIN change flow using sessions. [![Sequence diagram for changing PIN with sessions](https://docs.adyen.com/media/443ce0794cf4ed802da6ddc6a83703d401377003400a20548a7c0dd9bc83e0c8.svg)](https://docs.adyen.com/media/443ce0794cf4ed802da6ddc6a83703d401377003400a20548a7c0dd9bc83e0c8.svg) As shown in the diagram, the steps to change the PIN are: 1. [Load the application certificate](https://docs.adyen.com/issuing/manage-card-data/change-pin-sessions#load-certificate) when your application starts. 2. [Create a session instance](https://docs.adyen.com/issuing/manage-card-data/change-pin-sessions#create-session-instance). 3. [Change the PIN](https://docs.adyen.com/issuing/manage-card-data/change-pin-sessions#change-pin). ## 1. Load the application certificate Adyen provides you with an application certificate that you need to initialize Adyen's SDKs. The SDKs use this certificate to establish a secure session with Adyen. When your application starts: * Load the application certificate into your application. The following tabs show examples of how to load the certificate depending on which SDK you are using. ### Tab: iOS **Example of loading the certificate** ```swift guard let certificateUrl = Bundle.main.url(forResource: "adyen-certificate", withExtension: "der"), let certificate = try? Data(contentsOf: certificateUrl) else { fatalError("Missing Adyen app certificate") } ``` ### Tab: Android **Example of loading the certificate** ```kotlin val applicationCertificate = context.resources.openRawResource(R.raw.adyen_cert).use { val certFactory: CertificateFactory = CertificateFactory.getInstance("X.509") certFactory.generateCertificate(it) as X509Certificate } ``` ## 2. Create a session instance When a cardholder using your application selects the option to change the PIN, you must initialize the SDK. During initialization, you configure all objects and logic that handle your secure session with Adyen. The following tabs show examples of how to initialize Adyen's SDKs for iOS and Android. ### Tab: iOS To initialize a card session using the [Adyen Issuing SDK](https://github.com/Adyen/adyen-issuing-ios): 1. Create an instance of `CardSessions.Configuration`. Include the following parameters: * `appCertificate`: The certificate that you loaded when your application started. * `environment`: The target environment, either `.test` or `.live`. **Example instance of CardSessions.Configuration** ```swift let parameters = CardSessions.Configuration( appCertificate: certificate, environment: .test ) ``` 2. Define a token provider that retrieves the session token from Adyen, and then passes it from your backend to your client application. **Example of a token provider** ```swift struct MyTokenProvider: TokenProviding { func retrieveToken(for paymentInstrumentIds: Set) async throws -> SessionToken { let raw = try await myBackend.fetchSessionToken(for: paymentInstrumentIds) return SessionToken(raw) } } ``` 3. Initialize an instance of `CardSession` that creates a secure session with Adyen and retrieves a session token. Include the following: * In the `parameters` field, pass the `CardSessions.Configuration` object that you created. * In the `tokenProvider` field, pass an instance of the token provider that you defined. **Example instance of CardSession** ```swift let cardSession = CardSession( parameters: parameters, tokenProvider: MyTokenProvider() ) ``` ### Tab: Android To initialize a card session using the [Adyen Card Reveal Sessions SDK](https://github.com/Adyen/adyen-issuing-android): 1. Define a token provider that retrieves the session token from your backend after you [change the PIN](https://docs.adyen.com/issuing/manage-card-data/change-pin-sessions#change-pin). 2. Call the `CardSession.create` method. Include the following parameters: * `applicationCertificate`: The certificate that you loaded when your application started. * `sessionTokenProvider`: Pass an instance of the token provider that you defined. * `environment`: The target environment, either `CardSessionEnvironment.Test` or `CardSessionEnvironment.Live`. **Example of a call to CardSession.create** ```kotlin val result = CardSession.create( context = context, applicationCertificate = applicationCertificate, paymentInstrumentIds = setOf(paymentInstrumentId), environment = CardSessionEnvironment.Test, sessionTokenProvider = { networkClient.fetchSessionToken() } ) ``` 3. Implement logic to get the card session from the result of the `CardSession.create` method. **Handle the result of the CardSession.create method** ```kotlin val cardSession = when (result) { is CardSessionCreateResult.Success -> result.session else -> throw IllegalStateException("Error creating card session: $result") } ``` ## 3. Change the PIN After you initialize the SDK, you can create a secured session. Start the flow for a secured session by calling the `CardSession.changePin` SDK method. This method instructs the backend to make a request to our [Session authentication API](https://docs.adyen.com/api-explorer/sessionauthentication/latest/overview). Then, the SDK method retrieves the session data from the backend and returns it to your application. To create a secured session: 1. From your client application, call the [session instance](https://docs.adyen.com/issuing/manage-card-data/change-pin-sessions#create-session-instance) that you created. Pass the following parameters: * `paymentInstrumentId`: The payment instrument ID of the card. * `newPin`: The new PIN for the card. This method instructs the backend to make a request for a session. The following tabs show examples for iOS and Android. ### Tab: iOS **Example call to the changePin method—Example for iOS** ```swift try await cardSession.changePin( paymentInstrumentId: "PI00000000000000000000001", newPin: "5678" ) ``` ### Tab: Android **Example call to the changePin method—Example for Android** ```kotlin val pinChangeResult = cardSession.changePin( paymentInstrumentId = "PI00000000000000000000001", newPin = "5678" ) ``` 2. From your backend, make a POST [/sessions](https://docs.adyen.com/api-explorer/sessionauthentication/latest/post/sessions) request with the following parameters: | Parameter | Required | Description | | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- | | [product](https://docs.adyen.com/api-explorer/sessionauthentication/latest/post/sessions#request-product) | ![Required](https://docs.adyen.com/media/732127089c689593ccb0331d565e5773bed94e60145cae96672212374facb8c6.svg?decoding=auto\&fetchpriority=auto) | Set to **platform**. | | [policy.resources.type](https://docs.adyen.com/api-explorer/sessionauthentication/latest/post/sessions#request-policy-resources-type) | ![Required](https://docs.adyen.com/media/732127089c689593ccb0331d565e5773bed94e60145cae96672212374facb8c6.svg?decoding=auto\&fetchpriority=auto) | Set to **paymentInstrument**. | | [policy.resources.paymentInstrumentId](https://docs.adyen.com/api-explorer/sessionauthentication/latest/post/sessions#request-policy-resources-type-paymentInstrument-paymentInstrumentId) | ![Required](https://docs.adyen.com/media/732127089c689593ccb0331d565e5773bed94e60145cae96672212374facb8c6.svg?decoding=auto\&fetchpriority=auto) | The unique identifier of the payment instrument that the session applies to. | | [policy.roles](https://docs.adyen.com/api-explorer/sessionauthentication/latest/post/sessions#request-policy-roles) | ![Required](https://docs.adyen.com/media/732127089c689593ccb0331d565e5773bed94e60145cae96672212374facb8c6.svg?decoding=auto\&fetchpriority=auto) | An array of roles that define the allowed operations. Include the **PaymentInstrument: Pin Change** role. | **Create a session to change the PIN** #### curl ```bash curl https://test.adyen.com/authe/api/v1/sessions \ -H 'x-api-key: YOUR_API_KEY' \ -H 'content-type: application/json' \ -X POST \ -d '{ "product": "platform", "policy": { "resources": [ { "paymentInstrumentId": "PI00000000000000000000001", "type": "paymentInstrument" } ], "roles": [ "PaymentInstrument: Pin Change" ] } }' ``` #### Java ```java // Adyen Java API Library v38.0.0 to latest import com.adyen.Client; import com.adyen.Config; import com.adyen.enums.Environment; import com.adyen.model.*; import com.adyen.service.*; import java.math.*; import com.adyen.model.sessionauthentication.*; import java.time.OffsetDateTime; import java.util.*; import com.adyen.service.sessionauthentication.*; Config config = new Config() .apiKey("YOUR_API_KEY") .environment(Environment.TEST); Client client = new Client(config); // Create the request object(s) PaymentInstrumentResource resource1 = new PaymentInstrumentResource() .paymentInstrumentId("PI00000000000000000000001"); Policy policy = new Policy() .roles(Set.of("PaymentInstrument: Pin Change")) .resources(Set.of(resource1)); AuthenticationSessionRequest authenticationSessionRequest = new AuthenticationSessionRequest() .product(ProductType.PLATFORM) .policy(policy); // Send the request SessionAuthenticationApi service = new SessionAuthenticationApi(client); AuthenticationSessionResponse response = service.createAuthenticationSession(authenticationSessionRequest); ``` #### C\# ```cs // Adyen .NET API Library v35.0.0 to latest using System.Collections.Generic; using Adyen.SessionAuthentication.Extensions; using Adyen.SessionAuthentication.Models; using Adyen.SessionAuthentication.Services; using Adyen.Core.Client; using Adyen.Core.Client.Extensions; using Adyen.Core.Options; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; var host = Host.CreateDefaultBuilder() .ConfigureSessionAuthentication( (context, services, config) => { config.ConfigureAdyenOptions(options => { options.AdyenApiKey = "YOUR_API_KEY"; options.Environment = AdyenEnvironment.Test; }); services.AddAllSessionAuthenticationServices(); }) .Build(); var sessionAuthenticationService = host.Services.GetRequiredService(); // Create the request object(s) var resource1 = new PaymentInstrumentResource { PaymentInstrumentId = "PI00000000000000000000001" }; var policy = new Policy { Roles = new HashSet { "PaymentInstrument: Pin Change" }, Resources = new HashSet{ resource1 } }; var authenticationSessionRequest = new AuthenticationSessionRequest { Product = ProductType.Platform, Policy = policy }; // Send the request var result = await sessionAuthenticationService.CreateAuthenticationSessionAsync(authenticationSessionRequest); if (result.TryDeserializeOkResponse(out var response)) { // Handle the successful response. } ``` #### NodeJS (JavaScript) ```js // Adyen Node API Library v30.0.1 to latest const { Client, Config, EnvironmentEnum, SessionAuthenticationAPI } = require('@adyen/api-library'); const config = new Config({ apiKey: "YOUR_API_KEY", environment: EnvironmentEnum.TEST }); const client = new Client(config); // Create the request object(s) const resource1 = { type: "paymentInstrument", paymentInstrumentId: "PI00000000000000000000001" }; const policy = { roles: ["PaymentInstrument: Pin Change"], resources: [resource1] }; const authenticationSessionRequest = { product: "platform", policy: policy }; // Send the request const sessionAuthenticationAPI = new SessionAuthenticationAPI(client); const response = await sessionAuthenticationAPI.SessionAuthenticationApi.createAuthenticationSession(authenticationSessionRequest); ``` #### Python ```py # Adyen Python API Library v14.0.0 to latest import Adyen adyen = Adyen.Adyen() adyen.client.xapikey = "YOUR_API_KEY" adyen.client.platform = "test" # The environment to use library in. # Create the request object(s) json_request = { "product": "platform", "policy": { "resources": [{ "paymentInstrumentId": "PI00000000000000000000001", "type": "paymentInstrument" }], "roles": ["PaymentInstrument: Pin Change"] } } # Send the request result = adyen.sessionAuthentication.session_authentication_api.create_authentication_session(request=json_request) ``` #### Ruby ```rb # Adyen Ruby API Library v11.1.0 to latest require "adyen-ruby-api-library" adyen = Adyen::Client.new adyen.api_key = 'YOUR_API_KEY' adyen.env = :test # Set to "live" for live environment # Create the request object(s) request_body = { "product" => "platform", "policy" => { "resources" => [{ "paymentInstrumentId" => "PI00000000000000000000001", "type" => "paymentInstrument" }], "roles" => ["PaymentInstrument: Pin Change"] } } # Send the request result = adyen.session_authentication.session_authentication_api.create_authentication_session(request_body) ``` #### NodeJS (TypeScript) ```ts // Adyen Node API Library v32.1.0 to latest import { Client, Config, EnvironmentEnum, SessionAuthenticationAPI, Types } from "@adyen/api-library"; const config = new Config({ apiKey: "YOUR_API_KEY", environment: EnvironmentEnum.TEST }); const client = new Client(config); // Create the request object(s) const resource1: Types.sessionAuthentication.PaymentInstrumentResource = { type: Types.sessionAuthentication.ResourceType.PaymentInstrument, paymentInstrumentId: "PI00000000000000000000001" }; const policy: Types.sessionAuthentication.Policy = { roles: new Set(["PaymentInstrument: Pin Change"]), resources: new Set([resource1]) }; const authenticationSessionRequest = { product: Types.sessionAuthentication.ProductType.Platform, policy: policy } as unknown as Types.sessionAuthentication.AuthenticationSessionRequest; // Send the request const sessionAuthenticationAPI = new SessionAuthenticationAPI(client); const response = await sessionAuthenticationAPI.SessionAuthenticationApi.createAuthenticationSession(authenticationSessionRequest); ``` 3. Verify that the response contains a session [token](https://docs.adyen.com/api-explorer/sessionauthentication/latest/post/sessions#responses-200-token). **Session response** ```json { "id": "SESSION_ID", "token": "SESSION_TOKEN" } ``` 4. Pass the [token](https://docs.adyen.com/api-explorer/sessionauthentication/latest/post/sessions#responses-200-token) from your backend to the SDK. Use the token provider that you defined when you [initialized the SDK](https://docs.adyen.com/issuing/manage-card-data/change-pin-sessions#create-session-instance). If the request is successful, the SDK uses the token to establish a secure session with Adyen. The SDK uses the secure session to send the encrypted new PIN to Adyen. You do not need to make additional calls. The created session remains active for 5 minutes. ## Troubleshooting The following table describes errors the Adyen's SDKs can return and how to solve them. | Error | Description | Solution | | --------------- | ----------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Session expired | The session token has expired. | Create a new session from your server. | | Unauthorized | The session does not have the required role for the requested operation. | * Make sure that your API credential has access to the [Session authentication API](https://docs.adyen.com/api-explorer/sessionauthentication/latest/overview). * Make sure that you include the **PaymentInstrument: Pin Change** role in the request to [create the session](https://docs.adyen.com/issuing/manage-card-data/change-pin-sessions#change-pin). | | Forbidden | The payment instrument ID does not match the ID provided in the POST `/sessions` request. | Verify that the payment instrument ID matches the ID provided in the POST `/sessions` request. | ## See also * [Change PIN with the iOS SDK](https://docs.adyen.com/issuing/manage-card-data/change-pin-ios-sdk) * [Change PIN with standard encryption](https://docs.adyen.com/issuing/manage-card-data/change-pin)