The codec will be used for URI and URL components, and for HTTP Request and Response payloads carrying Content-Type
of application/x-www-form-urlencoded
.
Codec baseline
The baseline will be Percent Encoding with flavor of application/x-www-form-urlencoded
. Decoding is the encoding in reverse.
application/x-www-form-urlencoded
encodes ' '
(space) as '+'
(plus), newline is encoded as '%0D%0A'
, all except unreserved characters must be encoded with percent encoding in UTF-8 representation.
Hierarchical and primitive values
All hierarchical data structures must have a second encoding to fit into a single key=value pair, this applies for all top level values containing a data structure. The encoding is simple representation of JSON object or of JSON array as UTF-8 string.
Primitive values are encoded as is, without JSON representation.
Examples
{
response_type: "code",
scope: "openid",
client_id: "did:key:z2dmzD81cgPx8Vki7JbuuMmFYrWPgYoytykUZ3eyqht1j9KbsEYvdrjxMjQ4tpnje9BDBTzuNDP3knn6qLZErzd4bJ5go2CChoPjd5GAH3zpFJP5fuwSk66U5Pq6EhF4nKnHzDnznEP8fX99nZGgwbAh1o7Gj1X52Tdhf7U4KTk66xsA5r",
authorization_details: [{
type: "openid_credential",
format:"jwt_vc",
types:[
"VerifiableCredential",
"VerifiableAttestation",
"CTWalletInTime"
]
}],
redirect_uri: "openid:",
nonce: "glkFFoisdfEui43",
code_challenge: "YjI0ZTQ4NTBhMzJmMmZhNjZkZDFkYzVhNzlhNGMyZDdjZDlkMTM4YTY4NjcyMTA5M2Q2OWQ3YjNjOGJlZDBlMSAgLQo=",
code_challenge_method: "S256",
client_metadata: {
vp_formats_supported: {
jwt_vp: {
alg: ["ES256"]
},
jwt_vc: {
alg: ["ES256"]
}
},
response_types_supported: [
"vp_token",
"id_token"
],
authorization_endpoint: "openid:"
}
};
response_type=code
&scope=openid
&client_id=did%3Akey%3Az2dmzD81cgPx8Vki7JbuuMmFYrWPgYoytykUZ3eyqht1j9KbsEYvdrjxMjQ4tpnje9BDBTzuNDP3knn6qLZErzd4bJ5go2CChoPjd5GAH3zpFJP5fuwSk66U5Pq6EhF4nKnHzDnznEP8fX99nZGgwbAh1o7Gj1X52Tdhf7U4KTk66xsA5r
&authorization_details=%5B%7B%22type%22%3A%22openid_credential%22%2C%22format%22%3A%22jwt_vc%22%2C%22types%22%3A%5B%22VerifiableCredential%22%2C%22VerifiableAttestation%22%2C%22CTWalletInTime%22%5D%7D%5D
&redirect_uri=openid%3A
&nonce=glkFFoisdfEui43
&code_challenge=YjI0ZTQ4NTBhMzJmMmZhNjZkZDFkYzVhNzlhNGMyZDdjZDlkMTM4YTY4NjcyMTA5M2Q2OWQ3YjNjOGJlZDBlMSAgLQo%3D
&code_challenge_method=S256
&client_metadata=%7B%22vp_formats_supported%22%3A%7B%22jwt_vp%22%3A%7B%22alg%22%3A%5B%22ES256%22%5D%7D%2C%22jwt_vc%22%3A%7B%22alg%22%3A%5B%22ES256%22%5D%7D%7D%2C%22response_types_supported%22%3A%5B%22vp_token%22%2C%22id_token%22%5D%2C%22authorization_endpoint%22%3A%22openid%3A%22%7D
Objects, Arrays and primitives
{
obj: {
a: 1,
b: 2
},
arr: [ 1, 2, 3 ],
a: 1,
b: '2',
c: ' '
}
obj=%7B%22a%22%3A1%2C%22b%22%3A2%7D
&arr=%5B1%2C2%2C3%5D
&a=1
&b=2
&c=+
Javascript Example
URLSearchParams can be used to work with the application/x-www-form-urlencoded
. All top level data structures must be JSON stringified as UTF-8 before the conversion takes place, thus the algorithm would look like this.
function jsonStringifyNotPrimitive([key, value]) {
if (value == null) {
// filter out null and undefined values
return null;
}
if (typeof value === "object") {
// this includes arrays
return [key, JSON.stringify(value)];
}
return [key, value];
}
function encodeObject(o) {
return new URLSearchParams(
Object.fromEntries(
Object.entries(o).map(jsonStringifyNotPrimitive).filter(Boolean),
),
).toString();
}