/smooth-bankid

A howto for integrating Swedish BankID without all the fuzz

BankID integration made easy

These are instructions for integrating Swedish BankID that aim to be as succinct as possible. They should cover the needs of 99% of BankID integrations.

For a complete reference, refer to the official documentation available at bankid.com.

It's assumed that you are familiar with how BankID works from the users point of view. Armed with that knowledge, you should have all the important parts up and running within a couple of hours. Let's go.

Obtaining a test BankID

You will need a test BankID to be able to test your integration on the testing environment. As far as I know, you can't have both a test ID and your normal one installed on the same device, so you will need a dedicated testing device. For iOS you will use the regular client with some reconfiguring, but for Android you will have to install a custom APK that you can find here.

The instructions for installing the test identity can be found here. Complete this step before you move on with the guide.

Setting up your request agent

You have to configure your request agent to use the client SSL certificate provided by BankID. The specifics of how to do that will depend on your environment.

BankID provides a certificate in PFX format for use with the test environment, available here. The passphrase for this file is qwerty123. Switching to production later is a matter of using a different file (that your issuing bank will provide).

The public keys that you will be using to validate the identity of the responding server are:

Test

-----BEGIN CERTIFICATE-----
MIIF0DCCA7igAwIBAgIIIhYaxu4khgAwDQYJKoZIhvcNAQENBQAwbDEkMCIGA1UECgwbRmluYW5zaWVsbCBJRC1UZWtuaWsgQklEIEFCMRowGAYDVQQLDBFJbmZyYXN0cnVjdHVyZSBDQTEoMCYGA1UEAwwfVGVzdCBCYW5rSUQgU1NMIFJvb3QgQ0EgdjEgVGVzdDAeFw0xNDExMjExMjM5MzFaFw0zNDEyMzExMjM5MzFaMGwxJDAiBgNVBAoMG0ZpbmFuc2llbGwgSUQtVGVrbmlrIEJJRCBBQjEaMBgGA1UECwwRSW5mcmFzdHJ1Y3R1cmUgQ0ExKDAmBgNVBAMMH1Rlc3QgQmFua0lEIFNTTCBSb290IENBIHYxIFRlc3QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCAKWsJc/kV/0434d+Sqn19mIr85RZ/PgRFaUplSrnhuzAmaXihPLCEsd3Mh/YErygcxhQ/MAzi5OZ/anfuWSCwceRlQINtvlRPdMoeZtu29FsntK1Z5r2SYNdFwbRFb8WN9FsU0KvC5zVnuDMgs5dUZwTmdzX5ZdLP7pdgB3zhTnra5ORtkiWiUxJVev9keRgAo00ZHIRJ+xTfiSPdJc314maigVRQZdGKSyQcQMTWi1YLwd2zwOacNxleYf8xqKgkZsmkrc4Dp2mR5PkrnnKB6A7sAOSNatua7M86EgcGi9AaEyaRMkYJImbBfzaNlaBPyMSvwmBZzp2xKc9OD3U06ogV6CJjJL7hSuVc5x/2H04d+2I+DKwep6YBoVL9L81gRYRycqg+w+cTZ1TF/s6NC5YRKSeOCrLw3ombhjyyuPl8T/h9cpXt6m3y2xIVLYVzeDhaql3hdi6IpRh6rwkMhJ/XmOpbDinXb1fWdFOyQwqsXQWOEwKBYIkM6cPnuid7qwaxfP22hDgAolGMLY7TPKUPRwV+a5Y3VPl7h0YSK7lDyckTJdtBqI6d4PWQLnHakUgRQy69nZhGRtUtPMSJ7I4Qtt3B6AwDq+SJTggwtJQHeid0jPki6pouenhPQ6dZT532x16XD+WIcD2f//XzzOueS29KB7lt/wH5K6EuxwIDAQABo3YwdDAdBgNVHQ4EFgQUDY6XJ/FIRFX3dB4Wep3RVM84RXowDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBQNjpcn8UhEVfd0HhZ6ndFUzzhFejARBgNVHSAECjAIMAYGBCoDBAUwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBDQUAA4ICAQA5s59/Olio4svHXiKu7sPQRvrf4GfGB7hUjBGkYW2YOHTYnHavSqlBASHc8gGGwuc7v7+H+vmOfSLZfGDqxnBqeJx1H5E0YqEXtNqWG1JusIFa9xWypcONjg9v7IMnxxQzLYws4YwgPychpMzWY6B5hZsjUyKgB+1igxnfuaBueLPw3ZaJhcCL8gz6SdCKmQpX4VaAadS0vdMrBOmd826H+aDGZek1vMjuH11FfJoXY2jyDnlol7Z4BfHc011toWNMxojI7w+U4KKCbSxpWFVYITZ8WlYHcj+b2A1+dFQZFzQN+Y1Wx3VIUqSks6P7F5aF/l4RBngy08zkP7iLA/C7rm61xWxTmpj3p6SGfUBsrsBvBgfJQHD/Mx8U3iQCa0Vj1XPogE/PXQQq2vyWiAP662hD6og1/om3l1PJTBUyYXxqJO75ux8IWblUwAjsmTlF/Pcj8QbcMPXLMTgNQAgarV6guchjivYqb6Zrhq+Nh3JrF0HYQuMgExQ6VX8T56saOEtmlp6LSQi4HvKatCNfWUJGoYeT5SrcJ6snBy7XLMhQUCOXcBwKbNvX6aP79VA3yeJHZO7XParX7V9BB+jtf4tz/usmAT/+qXtHCCv9Xf4lv8jgdOnFfXbXuT8I4gz8uq8ElBlpbJntO6p/NY5a08E6C7FWVR+WJ5vZOP2HsA==
-----END CERTIFICATE-----

Prod

-----BEGIN CERTIFICATE-----
MIIFvjCCA6agAwIBAgIITyTh/u1bExowDQYJKoZIhvcNAQENBQAwYjEkMCIGA1UECgwbRmluYW5zaWVsbCBJRC1UZWtuaWsgQklEIEFCMRowGAYDVQQLDBFJbmZyYXN0cnVjdHVyZSBDQTEeMBwGA1UEAwwVQmFua0lEIFNTTCBSb290IENBIHYxMB4XDTExMTIwNzEyMzQwN1oXDTM0MTIzMTEyMzQwN1owYjEkMCIGA1UECgwbRmluYW5zaWVsbCBJRC1UZWtuaWsgQklEIEFCMRowGAYDVQQLDBFJbmZyYXN0cnVjdHVyZSBDQTEeMBwGA1UEAwwVQmFua0lEIFNTTCBSb290IENBIHYxMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAwVA4snZiSFI3r64LvYu4mOsI42A9aLKEQGq4IZo257iqvPH82SMvgBJgE52kCx7gQMmZ7iSm39CEA19hlILh8JEJNTyJNxMxVDN6cfJP1jMHJeTES1TmVbWUqGyLpyT8LCJhC9Vq4W3t/O1svGJNOUQIQL4eAHSvWTVoalxzomJhOn97ENjXAt4BLb6sHfVBvmB5ReK0UfwpNACFM1RN8btEaDdWC4PfA72yzV3wK/cY5h2k1RM1s19PjoxnpJqrmn4qZmP4tN/nk2d7c4FErJAP0pnNsll1+JfkdMfiPD35+qcclpspzP2LpauQVyPbO21Nh+EPtr7+Iic2tkgz0g1kK0IL/foFrJ0Ievyr3Drm2uRnA0esZ45GOmZhE22mycEX9l7w9jrdsKtqs7N/T46hil4xBiGblXkqKNG6TvARk6XqOp3RtUvGGaKZnGllsgTvP38/nrSMlszNojrlbDnm16GGoRTQnwr8l+Yvbz/ev/e6wVFDjb52ZB0Z/KTfjXOl5cAJ7OCbODMWf8Na56OTlIkrk5NyU/uGzJFUQSvGdLHUipJ/sTZCbqNSZUwboI0oQNO/Ygez2J6zgWXGpDWiN4LGLDmBhB3T8CMQu9J/BcFvgjnUyhyim35kDpjVPC8nrSir5OkaYgGdYWdDuv1456lFNPNNQcdZdt5fcmMCAwEAAaN4MHYwHQYDVR0OBBYEFPgqsux5RtcrIhAVeuLBSgBuRDFVMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU+Cqy7HlG1ysiEBV64sFKAG5EMVUwEwYDVR0gBAwwCjAIBgYqhXBOAQQwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBDQUAA4ICAQAJOjUOS2GJPNrrrqf539aN1/EbUj5ZVRjG4wzVtX5yVqPGcRZjUQlNTcfOpwPoczKBnNX2OMF+Qm94bb+xXc/08AERqJJ3FPKu8oDNeK+Rv1X4nh95J4RHZcvl4AGhECmGMyhyCea0qZBFBsBqQR7oC9afYOxsSovaPqX31QMLULWUYoBKWWHLVVIoHjAmGtAzMkLwe0/lrVyApr9iyXWhVr+qYGmFGw1+rwmvDmmSLWNWawYgH4NYxTf8z5hBiDOdAgilvyiAF8Yl0kCKUB2fAPhRNYlEcN+UP/KL24h/pB+hZ9mvR0tM6nW3HVZaDrvRz4VihZ8vRi3fYnOAkNE6kZdrrdO7LdBc9yYkfQdTcy0N+Aw7q4TkQ8npomrVmTKaPhtGhA7VICyRNBVcvyoxr+CY7aRQyHn/C7n/jRsQYxs7uc+msq6jRS4HPK8olnF9usWZX6KY+8mweJiTE4uN4ZUUBUtt8WcXXDiK/bxEG2amjPcZ/b4LXwGCJb+aNWP4+iY6kBKrMANs01pLvtVjUS9RtRrY3cNEOhmKhO0qJSDXhsTcVtpbDr37UTSqQVw83dReiARPwGdURmmkaheH6z4k6qEUSXuFch0w53UAc+1aBXR1bgyFqMdy7Yxib2AYu7wnrHioDWqP6DTkUSUeMB/zqWPM/qx6QNNOcaOcjA==
-----END CERTIFICATE-----

All three of those files (pfx, prod key, test key) are included in this repo, in the cert folder.

After you've configured the http agent, you're ready to start making API calls.

  • All calls are made as HTTP POST
  • Must include the header Content-Type: application/json
  • All parameters should be sent as JSON in the request body
  • For all the methods covered below, calling them is a matter of making a POST request to BASE_URL/METHOD_NAME

The base URL for the test environment is https://appapi2.test.bankid.com/rp/v5, and production is located at https://appapi2.bankid.com/rp/v5. These may not be the most current ones when you're reading this, but they should remain available indefinitely at the given locations.

Authentication

To initiate authentication, call the auth endpoint (for example https://appapi2.test.bankid.com/rp/v5/auth) with the following parameters.

Name Required Example Description
endUserIp Yes "213.112.83.16"
personalNumber Yes* "198006211414" Required for the "other device" flow. For "same device" it's optional.
requirement No {} Object containing various flags. For "same device" flow, pass certificatePolicies: ['1.2.752.78.1.5']. Another useful requirement is allowFingerprint: true. You probably won't ever need any of the other possible fields.

Making this call will trigger the authorization flow in the users BankID app.

Signing

To initiate signing, use the sign endpoint.

Name Required Example Description
endUserIp Yes "213.112.83.16"
userVisibleData Yes "SmFnIGludHlnYXIgYXR0IGphZyB2aWxsIHNrcml2YSBww6UgZG9rdW1lbnRldC4=" Base64 encoded string containing the text you want the user to sign.
personalNumber Yes* "198006211414" See auth.
requirement No {} See auth.

Making this call will trigger the signing flow in the users BankID app.

Launching the native client

The auth and sign calls return an autoStartToken that can be used to construct a url that can be launched on the users device and picked up by the BankID app, if it is installed.

On iOS, the url should be constructed like this:

https://app.bankid.com/?autostarttoken=[AUTOSTART_TOKEN_HERE]&redirect=null

On any other device, use this format:

bankid:///?autostarttoken=[AUTOSTART_TOKEN_HERE]&redirect=null

According to the documentation, the order of the query parameters matters, so don't change it or add any other parameters.

The brackets around the autoStartToken should be included. In other words, this is a valid url:

bankid:///?autostarttoken=[bdaccd84-6a98-4276-ba70-35e944b704af]&redirect=null

And this is not:

bankid:///?autostarttoken=bdaccd84-6a98-4276-ba70-35e944b704af&redirect=null

Polling for results

Both the sign and auth endpoints return objects that contain the fields autoStartToken and orderRef. You will need to poll the collect method to retrieve the status of an ongoing operation.

Documentation states that you should call collect every two seconds but specifically not more often than once per second.

The collect method takes a single parameter – orderRef – and returns two out of three values: status, hintCode and completionData.

If status is pending, keep polling. If status is complete or failed, the flow has finished. For failed and pending orders, hintCode will provide more information on the reason/state. For completed orders, completionData will be an object containing information on the user.

Cancelling an ongoing order

Call cancel with a single parameter – orderRef. Any ongoing orders must be cancelled before the user can start a new order.

Tying it together

Those four methods, auth, sign, collect, and cancel are all you need to get your integration working. Once you get this far though, you'll need to refer to the official docs to ensure you're in compliance with all of the specific requirements therein. For example, certain failstates require you to display specific error messages, and certain data must always be persisted to disk.

Examples