📸
CardScan.ai Documentation
  • Introduction 👋🏻
  • Design Goals 🎨
  • Authentication 🔐
  • API 💻
  • UI Components
    • React ⚛
    • React Native ⚛
    • Flutter 🦅
    • iOS 📱
    • Android 🤖
    • Customization ⚙️
  • Advanced Features
    • Camera Permission Modal 📸
    • Eligibility Verification 🩻
    • Payer Matching 🔍
    • Web to Mobile Handoff 📲
Powered by GitBook
On this page
  • Server-to-server
  • End User
  • Authentication Pattern

Was this helpful?

Authentication 🔐

PreviousDesign Goals 🎨NextAPI 💻

Last updated 1 year ago

Was this helpful?

This API support authentication for two different kinds of use cases:

  • - backend systems, admin portals, etc.

  • - a patient or clinician most likely on mobile or the web.

Jump down to example

Server-to-server

authenticates server-to-server (S2S) API requests using your account's API keys. A request without an API key, or with an expired, or revoked key, will cause the API to return an error.

Every account has separate keys for testing on our sandbox, or for running live in production. The sandbox API is identical to the production API.

The sandbox API is not HIPPA compliant and should NOT be used for PHI.

API Keys

Your API Keys are available on the Dashboard. The API Keys start with a prefix to clearly distinguish their usage.

For accessing the API in the sandbox environment use keys with this format:

  • secret_test_XXXXXXXXXXXXXXX

When you are ready for production or live mode, use keys with this format:

  • secret_live_XXXXXXXXXXXXXXX

Read more about sandbox vs live mode on the page

API Keys are like passwords, keep them safe and NEVER use them in a client-side application.

End User

curl --request GET 'https://sandbox.cardscan.ai/v1/access-token' \
--header 'Authorization: Bearer secret_test_XXXXXXXXXXXXXXX'
import requests

url = "https://sandbox.cardscan.ai/v1/access-token"

headers = {
  'Authorization': 'Bearer secret_test_XXXXXXXXXXXXXXX'
}

response = requests.request("GET", url, headers=headers)
print(response.json())
var axios = require('axios');

url = 'https://sandbox.cardscan.ai/v1/access-token'

var options = {
    headers: { 
        'Authorization': 'Bearer secret_test_XXXXXXXXXXXXXXX'
    }
}

axios.get(url, options)
  .then(function (response) {
    console.log(JSON.stringify(response.data))
  })
  .catch(function (error) {
    console.log(error);
});

By default end users lose access to uploaded cards and all associated data when their session token expires. To prevent this pass in a user_id as a query parameter to the /access-token endpoint. The user_id parameter must be unique across your user base, we recommend using an email address or internal uuid identifier.

WARNING: using a non-unique user_id will result in PHI exposure

curl --request GET 'https://sandbox.cardscan.ai/v1/access-token?user_id=d77176fb-be40-4884-b9bb-ca64f657804b' \
--header 'Authorization: Bearer secret_test_XXXXXXXXXXXXXXX'

Server-to-server requests continue to have access to uploaded cards and associated data, even after the end user's session has expired.

Authentication Pattern

Below are two overly simplified examples of this workflow for Flask and Express:

import requests
from flask_login import login_required, current_user


@app.route('/cardscan-session')
@login_required
def session():
    '''
    Generates a cardscan.ai token for the logged-in user and returns it.
    '''
    url = "https://sandbox.cardscan.ai/v1/access-token"
    params = {
        'user_id': current_user.id
    }
    headers = {
        'Authorization': 'Bearer secret_test_XXXXXXXXXXXXXXX'
    }
    response = requests.request("GET", url, params=params, headers=headers)
    response.raise_for_status()
    payload = response.json()

    return jsonify(payload)
const router = express.Router();
var axios = require('axios');

router.get('/cardscan-session', (req, res) => {

    url = 'https://sandbox.cardscan.ai/v1/access-token'

    var options = {
        headers: { 
            'Authorization': 'Bearer secret_test_XXXXXXXXXXXXXXX'
        },
        params: {
            'user_id': req.auth.user
        }
    }

    axios.get(url, options)
      .then(function (response) {
        res.setHeader('Content-Type', 'application/json');
        res.end(JSON.stringify(response.data));
      })
      .catch(function (error) {
        //Handle error
        res.status(error.response.status);
        res.end(error.response.data.message);
    });
});
private func didTapScanCard(_ sender: UIButton) {

    button.showLoaderAboveImage(userInteraction:true)

    var request = URLRequest(url: URL(string: "https://{{YOUR_SERVER_BASE_URL}}/cardscan-session")!)
    request.httpMethod = "GET"
    request.setValue("application/json", forHTTPHeaderField: "Accept")
      
    URLSession.shared.dataTask(with: request) { [weak self] data, response, error in
        
           ///Extract session from server response
            guard error == nil,
              let data = data,
              let json = try? JSONDecoder().decode([String: String].self, from: data),
            let session = json["session"] else {

            //handle errors calling server. :-(
            print("Error calling server: ", error as Any)
            return
        }
        
        ///Trigger presentation of CardScannerView with user's session token.
        DispatchQueue.main.async { [weak self] in
            self?.presentCardScanner(userToken: session)
        }
    }.resume()
}

private func presentCardScanner(userToken: String) {
    
    ///Create CardScannerView with user session token
    let cardScannerViewController = CardScannerViewController(userToken: userToken, live: true)
    
    cardScannerViewController.present(from: self, animated:true) { result in 
        print(result)
    }
}
import { useEffect, useState } from "react";
import CardScanView from "react-cardscan-ai";

const Onboarding = () => {
  const [token, setToken] = useState("");
  
  const onSuccess = (card: any) => {
    console.log("success!");
  };
  
  const loadScanView = () => {  
  
    fetch("https://{{YOUR_SERVER_BASE_URL}}/cardscan-session", {
      method: "POST",
    })
      .then((res) => res.json())
      .then((data) => {
        setToken(data.session);
      })
      .catch((err) => console.log(err));
  };
    
    return (
      <div>
        { (token.trim() == "") ?
        <button onClick={loadScanView}>Start Scanning</button>;
        : 
        <CardScanView
          live={false}
          sessionToken={token}
          onSuccess={onSuccess}
        />
      });
};

export default Onboarding;
class OnboardingActivity : AppCompatActivity(), CardScanActivityResult {

    lateinit var cardScanResultLauncher : ActivityResultLauncher<Intent>

    private fun getSession(callback: (session: String) -> Unit) {
        val httpAsync = "https://{{YOUR_SERVER_BASE_URL}}/cardscan-session"
            .httpPost()
            .responseJson { _, _, result ->
                //check for errors :)
                val jsonObject = result.get().obj()
                val session = jsonObject["session"] as String
                callback(session)
            }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_onboarding)

        
        cardScanResultLauncher =  registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
           CardScanActivity.processResult(this@MainActivity, result)
       }

        findViewById<View>(R.id.scanCardButton).setOnClickListener { _ ->
            getSession { session ->
                //trigger the loading of CardScanActivity with user's session token
                CardScanActivity.start(
                    activity = this,
                    resultLauncher = cardScanResultLauncher,
                    sessionToken = session
                )
            }

        }
    }

    override fun scanSuccess(card: CardData) {
        Log.d("CardScan", "ScanSuccess $card")
    }

}

End users on all platforms (web, mobile, etc) authenticate with the APIs using a sessionToken. This token is a short-lived JSON Web Token (JWT).

Requesting a token is done via the endpoint.

The recommended pattern for authenticating end users is to create a authentication endpoint on the customer's backend servers. In the diagram below the endpoint is called /cardscan-session and is responsible for authenticating the end user before requesting a session token from the API.

Once a session has been generated, it can be used to initialize the SDK and UI Components, or used to call the API directly. This allows the end user's browser or mobile device to safely and securely connect with the servers.

Cardscan.ai
CardScan.ai
CardScan.ai
CardScan.ai
CardScan.ai
Server-to-server
End User
authentication patterns
Auth Diagram
API Endpoints
Access Token