Private Key JWT¶
We recommend using private_key_jwt
as Client Authentication towards BankID.
As per the standard you must authenticate your application when calling:
or, any other resource APIs (e.g. BankID Signing).
Requirements¶
In order to use private_key_jwt
you need to:
- generate a keypair
- build a JWKS according to spec with your public key(s)
- submit JWKS to BankID support (or update your client in Stø Portal)
Multiple keys per Client
A Client may have multiple keys associated with it (JWKS). They are each distingushed by the kid
(Key ID).
This is useful for key rotation.
Generate JWKS¶
In order to register your public key you need to provide the key in JWKS format.
This format is represented as an array of JWKs under the keys
field.
An example JWKS may look like this:
{
"keys":[
{
"kty":"EC",
"crv":"P-256",
"alg":"ES256",
"x":"MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4",
"y":"4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM",
"use":"sig",
"kid":"fpy9BfdmvVRubt5VN5Ct263YO5dpMi37nd1OKcJIzOQ"
},
{
"kty":"RSA",
"n": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx
4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMs
tn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2
QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbI
SD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqb
w0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw",
"e":"AQAB",
"alg":"RS256",
"use":"sig",
"kid":"-b1ua3CUopwJCcLjCGslrpJsLSAFiDVGKK2yLehXMaE"
}
]
}
The requirements for the JWK are:
Claim | Description | Example |
---|---|---|
kty |
key type | RSA or EC |
alg |
algorithm | ES256 or RS256, but see also token_endpoint_auth_signing_alg_values_supported list of supported algorithms. |
use |
Usage. Must be sig |
sig |
kid |
Key ID. This you can generate as you wish, but it is important for key rotation. | RKylPNVyCN8wIO5L55LnIwV7IPh0sErQQzn--CD1xk8 |
Then depending on key type you may have the actual key data encoded in fields such as:
n
ande
for RSAcrv
,x
andy
for EC
KID generation
One way to generate the KID could be the Base64Url encoded SHA-256 digest of the public key.
Send us the JWKS¶
After building the JWKS, you can send it to us via a BankID Support case, or use the Stø Portal (depending on access and availability), if you are a partner with us.
We do not support URL to JWKS endpoint. You need to send us the JWKS for the Client.
Usage¶
Build JWT assertion claim¶
When you are going to call the Token endpoint (or any other protected resource), you need to:
- build a JWT according to the table below.
- sign JWT using a private key.
The requirements for the JWT are:
Claim | Required | Description |
---|---|---|
aud |
yes | The endpoint to call. E.g. token endpoint. E.g. https://auth.current.bankid.no/auth/realms/current/protocol/openid-connect/token |
sub |
yes | The subject of this token, which is your Client ID. E.g. some-client-bankid-current |
iss |
yes | The issuer of this token, which is your Client ID. Same as subject. E.g some-client-bankid-current |
jti |
yes | A unique token identifier. Cannot be used several times. E.g. a2a39ffb-4899-43be-9938-560653778cd2 |
exp |
yes | The token expiration time in seconds since Epoch (UNIX timestamp). E.g. 1759835872 |
ait |
no | When the token was issued in seconds since Epoch (UNIX timestamp). E.g. 1759815872 |
Example decoded JWT with header and signature¶
{
"typ": "JWT",
"kid": "-b1ua3CUopwJCcLjCGslrpJsLSAFiDVGKK2yLehXMaE",
"alg": "RS256"
}
.
{
"aud" : "https://auth.current.bankid.no/auth/realms/current/protocol/openid-connect/token",
"iss" : "some-client-bankid-current",
"sub" : "some-client-bankid-current",
"jti" : "a3a2fc6e-29e3-4b4d-9284-615982c213c4",
"exp" : "1759835872",
"iat" : "1759815872"
}
.
9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGj...
Always add the kid
of the key used in the JWT header.
Add client assertion parameters to request¶
Parameter | Description |
---|---|
client_assertion | The client assertion is the signed JWT in Base64Url encoding. |
client_assertion_type | The type of client_assertion. This value is always url encoded urn:ietf:params:oauth:client-assertion-type:jwt-bearer . |
Example Token Request with private_key_jwt
¶
POST /auth/realms/current/protocol/openid-connect/token HTTP/1.1
Host: auth.current.bankid.no
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&code=Gw30fMKJBHkcOBSde5awLrMm4ahvgCNM2cFSTUOUflY
&redirect_uri=https://example.org/callback
&client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer
&client_assertion=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...
Key rotation¶
We support multiple keys per Client (JWKS) which makes it trivial to rotate the keys when needed.
If you want to add a new key for the Client, just contact BankID support (or your BankID Partner) with the new key as part of the JWKS. Then update it again to remove the old key after minimum 24 hours.
If you need to revoke a key, just contact BankID support (or your BankID Partner) with the revoked key gone, and new key added as part of the JWKS. Mark the ticket it as high priority and add REVOKE to the subject.