Delete A Card from the Virgil CloudThis guide shows how to delete (deactivate) a Virgil Card, which is associated with a user or device, and a corresponding public key on the Virgil Cloud.There are three ways to delete a Virgil Card:using the Virgil E3Kit SDKusing the Virgil Core SDKusing the Virgil Cards Service APIIn this guide you'll find out how to delete a Card using Virgil E3Kit SDK or Core SDK.How card deletion worksWhen you use the Virgil SDK to delete a user's card, you don't fully delete it from the Virgil Cloud, you only deactivate (revoke) the card by updating (replacing) an active Virgil Card with a new one that has an empty public key. A user's card that is going to be deleted, should have the same identity which is used to generate a JWT. Any deactivated cards will still be available to application users by searching the card by its ID.Prerequisites for card deletionIn this tutorial we assume that you have a basic backend server for your app. Your server must be able to create and store user records in persistent storage and provide a user authentication strategy, whether it's a simple username/password or a third-party provider like GitHub or Facebook.To give your users access to the Virgil Cloud you'll need to setup authentication on your server side and provide users with a JWT for the client-side SDK's initialization. Go through this guide to setup your application's backend.Delete a Card with the E3Kit SDKTo deactivate (unregister) a user from the Virgil Cloud, you have to initialize the E3Kit SDK on the client side.Initialize the E3Kit SDKMORE GitHubEThree.initialize(context, new OnGetTokenCallback() { @NotNull @Override public String onGetToken() { return virgilToken; } }).addCallback(new OnResultListener() { @Override public void onSuccess(EThree result) { // Init success } @Override public void onError(@NotNull Throwable throwable) { // Error } });GitHubimport { EThree } from '@virgilsecurity/e3kit'; // This function returns a token that will be used to authenticate requests // to your backend. // This is a simplified solution without any real protection, so here you need use your // application authentication mechanism. async function authenticate(identity) { const response = await fetch('http://localhost:3000/authenticate', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ identity: identity }) }); if (!response.ok) { throw new Error(`Error code: ${response.status} \nMessage: ${response.statusText}`); } return response.json().then(data => data.authToken); } // Log in as `alice` const eThreePromise = authenticate('alice').then(authToken => { // E3kit will call this callback function and wait for the Promise resolve. // When it receives Virgil JWT it can do authorized requests to Virgil Cloud. // E3kit uses the identity encoded in the JWT as the current user's identity. return EThree.initialize(getVirgilToken); // This function makes authenticated request to GET /virgil-jwt endpoint // The token it returns serves to make authenticated requests to Virgil Cloud async function getVirgilToken() { const response = await fetch('http://localhost:3000/virgil-jwt', { headers: { // We use bearer authorization, but you can use any other mechanism. // The point is only, this endpoint should be protected. Authorization: `Bearer ${authToken}`, } }) if (!response.ok) { throw new Error(`Error code: ${response.status} \nMessage: ${response.statusText}`); } // If request was successful we return Promise which will resolve with token string. return response.json().then(data => data.virgilToken); } }); // then you can get instance of EThree in that way: eThreePromise.then(eThree => { /* eThree.encrypt/decrypt/lookupPublicKeys */}) // or const eThree = await eThreePromise;GitHub// Init e3kit (EThree) SDK EThree.initialize(context, object : OnGetTokenCallback { override fun onGetToken(): String { return virgilToken } }).addCallback(object : OnResultListener { override fun onSuccess(result: EThree) { // Init success } override fun onError(throwable: Throwable) { // Error } })GitHubimport VirgilE3Kit import VirgilSDK let connection = HttpConnection() // This function returns a token that will be used to authenticate requests // to your backend. // This is a simplified solution without any real protection, so here you need // use your application authentication mechanism. let authCallback = { () -> String in let url = URL(string: "http://localhost:3000/authenticate")! let headers = ["Content-Type": "application/json"] let params = ["identity": identity] let requestBody = try! JSONSerialization.data(withJSONObject: params, options: []) let request = Request(url: url, method: .post, headers: headers, body: requestBody) let resonse = try! connection.send(request) let json = try! JSONSerialization.jsonObject(with: resonse.body!, options: []) as! [String: Any] let authToken = json["authToken"] as! String return authToken } let authToken = authCallback() let url = URL(string: "http://localhost:3000/virgil-jwt")! // We use bearer authorization, but you can use any other mechanism. // The point is only, this endpoint should be protected. let headers = ["Content-Type": "application/json", "Authorization": "Bearer " + authToken] // This function makes authenticated request to GET /virgil-jwt endpoint // The token it returns serves to make authenticated requests to Virgil Cloud let tokenCallback: EThree.RenewJwtCallback = { completion in let request = Request(url: url, method: .get, headers: headers) guard let response = try? connection.send(request), let body = response.body, let json = try? JSONSerialization.jsonObject(with: body, options: []) as? [String: Any], let jwtString = json?["virgilToken"] as? String else { completion(nil, AppError.gettingJwtFailed) return } completion(jwtString, nil) } let eThree = try EThree(identity: identity, tokenCallback: tokenCallback)Then use the eThree.unregister() method which will delete the private key from local storage, reversing the actions of the register function.MORE // TODO: init and register user (see EThree.initialize and EThree#register) OnCompleteListener unregisterListener = new OnCompleteListener() { @Override public void onSuccess() { // Public key (Card) revoked successfully, private key removed successfully. } @Override public void onError(@NotNull Throwable throwable) { // Handle error } }; // Revokes Card from Virgil Cards Service, deletes Private Key from local storage eThree.unregister().addCallback(unregisterListener);GitHub// TODO: init and register user (see eThree.initialize and eThree.register) // Revokes Card from Virgil Cards Service, deletes Private Key from local storage await eThree.unregister(); // or eThree.unregister() .then(() => console.log('success')) .catch(e => console.error('error: ', e));// TODO: init and register user (see EThree.initialize and EThree.register) val unregisterListener = object : OnCompleteListener { override fun onSuccess() { // Public key (Card) revoked successfully, private key removed successfully. } override fun onError(throwable: Throwable) { // Handle error } } // Revokes Card from Virgil Cards Service, deletes Private Key from local storage eThree.unregister().addCallback(unregisterListener)GitHubimport VirgilE3Kit // TODO: init and register user (see EThree.init and EThree.register) // Revokes Card from Virgil Cards Service, deletes Private Key from local storage eThree.unregister { error in guard error == nil else { // Error handling here } }Delete A Card with the Core SDKThe Virgil Core SDK allows you to delete user cards on the Virgil Cloud from the client side or from an application server.In order to deactivate a user's card, you have to:Install Core SDK & Setup Crypto librarySet up a device storage for Private KeysSet up a jwtProvider to request a JWTSet up and initialize a Card ManagerThen use the following lines of code to deactivate the user's card:MORE GitHubtry { cardManager.revokeCard(card.getIdentifier()); } catch (Exception e) { // Error handling }GitHubcardManager.revokeCard(myCardId) .then(() => console.log('Card revoked'));import VirgilSDK let result = cardManager.revokeCard(withId: card.identifier).start { result in switch result { // Card is revoked case .success: break // Error occured case .failure(let error): break } }