Skip to content

Commit 089d667

Browse files
authored
Merge pull request #1078 from webauthn4j/alternative-ponyfill
Introduce github/webauthn-json pony-fill in the reference doc
2 parents 6905557 + aabef3e commit 089d667

File tree

4 files changed

+101
-4
lines changed

4 files changed

+101
-4
lines changed

docs/src/reference/asciidoc/en/deep-dive.adoc

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,50 @@ In general, you can serialize and deserialize it by the method explained in <<Cr
117117
A `ObjectConverter` with a `DeviceCheckCBORModule` can be obtained with `DeviceCheckManager.createObjectConverter` static method.
118118

119119

120+
=== Alternative to Unsupported JSON Serialization APIs in Safari
121+
122+
In the Quick Start, `PublicKeyCredential.parseCreationOptionsFromJSON` is introduced as an API for parsing `PublicKeyCredentialCreationOptions`, and `PublicKeyCredential#toJSON` as an API for serializing `PublicKeyCredential`. However, as of today(December 2024), these APIs are not available in Safari.
123+
124+
As an alternative, it is recommended to use the pony-fill provided by the npm library https://github.com/github/webauthn-json[github/@webauthn-json], maintained by GitHub.
125+
It provides `parseCreationOptionsFromJSON` method as a substitute for `PublicKeyCredential.parseCreationOptionsFromJSON` and `create` as a substitute for `navigator.credentials.create`.
126+
127+
.github/@webauthn-json: Creating a credential
128+
[source,javascript,caption="Example {counter:number}: "]
129+
----
130+
import {
131+
create,
132+
parseCreationOptionsFromJSON,
133+
} from "@github/webauthn-json/browser-ponyfill";
134+
135+
const response = await fetch("<endpoint path that returns PublicKeyCredentialCreationOptions as JSON>") //fetch PublicKeyCredentialCreationOptions as JSON string
136+
const publicKeyCredentialCreationOptionsJSON = await response.json() // convert to JSONObject
137+
const credentialCreationOptions = parseCreationOptionsFromJSON(publicKeyCredentialCreationOptionsJSON); // convert to PublicKeyCredentialCreationOptions
138+
const publicKeyCredential = await create({ publicKey: credentialCreationOptions}); // create PublicKeyCredential
139+
const registrationResponseJSON = publicKeyCredential.toJSON() // JSON object of publicKeyCredential
140+
const registrationResponseJSONStr = JSON.stringify(registrationResponseJSON) // JSON string representation of publicKeyCredential
141+
----
142+
143+
The `toJSON` method can be used on the publicKeyCredential obtained using the `create` method of this pony-fill.
144+
145+
It also provides `parseRequestOptionsFromJSON` as a substitute for `PublicKeyCredential.parseRequestOptionsFromJSON`, and `get` is provided as a substitute for `navigator.credentials.get`.
146+
147+
.github/@webauthn-json: Getting a credential
148+
[source,javascript,caption="Example {counter:number}: "]
149+
----
150+
import {
151+
get,
152+
parseRequestOptionsFromJSON,
153+
} from "@github/webauthn-json/browser-ponyfill";
154+
155+
const response = await fetch("<endpoint path that returns PublicKeyCredentialRequestOptions as JSON>");
156+
const publicKeyCredentialRequestOptionsJSON = await response.json();
157+
const credentialGetOptions = parseRequestOptionsFromJSON(publicKeyCredentialRequestOptionsJSON);
158+
const publicKeyCredential = await get({ publicKey: credentialGetOptions });
159+
const authenticationResponseJSON = publicKeyCredential.toJSON();
160+
const authenticationResponseJSONStr = JSON.stringify(authenticationResponseJSON);
161+
----
162+
163+
120164
// === async support
121165
//
122166
// TODO: explain webauthn4j-core-async

docs/src/reference/asciidoc/en/quick-start.adoc

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,11 @@ If no wrapper library is available, you will need to implement these functions y
146146

147147
When calling the `navigator.credentials.create` method, various options can be specified. One of these options is `challenge`. As mentioned earlier, the challenge is a parameter used to prevent replay attacks; it should be generated by the server, passed as a parameter, and also saved in a session or similar storage.
148148
According to the registration flow diagram, the backend server first generates the challenge, saves it in a session, and then sends it to the client.
149-
The WebAuthn specification does not define a specific method for passing the challenge from the backend server to the frontend. You could embed it in an HTML page or set up a REST endpoint to return the challenge. Another good idea is to create an endpoint that returns the entire `PublicKeyCredentialCreationOptions`, a parameter for `navigator.credentials.create`. The WebAuthn JavaScript API provides a method called `PublicKeyCredential.parseCreationOptionsFromJSON`, which can parse a serialized JSON `PublicKeyCredentialCreationOptions`. WebAuthn4J offers a Java class representing `PublicKeyCredentialCreationOptions`, which can be useful for assembling JSON on the backend server.
149+
The WebAuthn specification does not define a specific method for passing the challenge from the backend server to the frontend. You could embed it in an HTML page or set up a REST endpoint to return the challenge. Another good idea is to create an endpoint that returns the entire `PublicKeyCredentialCreationOptions`, a parameter for `navigator.credentials.create`. The WebAuthn JavaScript API provides a method called `PublicKeyCredential.parseCreationOptionsFromJSON`, which can parse a serialized JSON `PublicKeyCredentialCreationOptions`.
150+
However, as of December 2024, `PublicKeyCredential.parseCreationOptionsFromJSON` is not available in Safari.
151+
For alternative solutions, refer to <<./deep-dive.adoc#_alternative_to_unsupported_json_serialization_apis_in_safari, Alternative to Unsupported JSON Serialization APIs in Safari>>.
152+
153+
WebAuthn4J offers a Java class representing `PublicKeyCredentialCreationOptions`, which can be useful for assembling JSON on the backend server.
150154

151155
.Fetching the entire `PublicKeyCredentialCreationOptions` from the REST endpoint and calling `navigator.credentials.create`
152156
[source,javascript,caption="Example {counter:number}: "]
@@ -166,6 +170,8 @@ The generated WebAuthn credential must be sent to the backend server in some way
166170
The WebAuthn specification does not define the format in which it should be sent to the server.
167171
However, the JavaScript type `PublicKeyCredential`, representing a WebAuthn credential, has a `toJSON` method.
168172
Using this method along with `JSON.stringify` to serialize the data is considered a best practice for transmission.
173+
However, this `toJSON` method is also not available in Safari.
174+
For alternative solutions, refer to <<./deep-dive.adoc#Alternative-to-Unsupported-JSON-Serialization-APIs-in-Safari,Alternative to Unsupported JSON Serialization APIs in Safari>>.
169175

170176
.Sending `PublicKeyCredential`
171177
[source,javascript,caption="Example {counter:number}: "]
@@ -249,7 +255,7 @@ The server state is encapsulated in `serverProperty`. When calling the `ServerPr
249255
- For `challenge`, set the generated challenge. The challenge is a parameter that helps prevent replay attacks. Generate a random byte array on the server as the challenge, pass it to the WebAuthn JS API on the frontend, and include it in the data to be signed. The server then verifies the matching values to protect users from replay attacks. It is the responsibility of the WebAuthn4J caller to persist the generated challenge until verification; storing it in a session is recommended.
250256

251257
If verification succeeds, create a `CredentialRecord` instance from the returned values and persist it in a database or similar storage for authentication.
252-
For more information on persistence methods, see <<credentialrecord-serialization-and-deserialization>>.
258+
For more information on persistence methods, see <<_credentialrecord_serialization_and_deserialization, Credential Record serialization and deserialization>>.
253259
If verification fails, a subclass of `VerificationException` will be thrown.
254260

255261
=== Implementing the Authentication Process Using WebAuthn4J
@@ -260,6 +266,7 @@ The primary API used during WebAuthn authentication is the browser’s `navigato
260266
This is necessary because the `navigator.credentials.get` method requires a `challenge` parameter.
261267
The WebAuthn specification does not define a specific method for transferring the challenge from the backend server to the frontend (client) for authentication.
262268
Just as with the registration process, feel free to use any preferred method to pass the challenge to the frontend. The JavaScript API for parsing `PublicKeyCredentialGetOptions`, a parameter of `navigator.credentials.get`, is `PublicKeyCredential.parseCreationGetOptionsFromJSON`.
269+
For alternative solutions to the issue that `PublicKeyCredential.parseCreationGetOptionsFromJSON` is not available in Safari, refer to <<./deep-dive.adoc#_alternative_to_unsupported_json_serialization_apis_in_safari,Alternative to Unsupported JSON Serialization APIs in Safari>>.
263270
For additional options that can be specified for the `navigator.credentials.get` method, please refer https://developer.mozilla.org/en-US/docs/Web/API/CredentialsContainer/get[MDN: CredentialsContainer: get() method].
264271

265272

docs/src/reference/asciidoc/ja/deep-dive.adoc

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,49 @@ webauthn4j-appattestでは、`CredentialRecord` インタフェースの代わ
107107
`ObjectConverter` は `DeviceCheckCBORModule` が登録されたものを使用する必要があります。
108108
`DeviceCheckCBORModule` が登録された `ObjectConverter` は `DeviceCheckManager#createObjectConverter` で得ることが出来ます。
109109

110+
=== Safariで未サポートなJSON serialization APIsの代替
111+
112+
クイックスタートでは、 `PublicKeyCredentialCreationOptions` をパースするAPIとして `PublicKeyCredential.parseCreationOptionsFromJSON` が、
113+
`PublicKeyCredential` をシリアライズするAPIとして `PublicKeyCredential#toJSON` が存在すると紹介しましたが、2024/12現在、Safariでは利用できません。
114+
代わりとして、GitHubが提供するnpmライブラリ、 https://github.com/github/webauthn-json[github/@webauthn-json] が提供する、 pony-fillを利用するのがお勧めです。
115+
`PublicKeyCredential.parseCreationOptionsFromJSON` の代わりに、 `parseCreationOptionsFromJSON` が、
116+
`naviagator.credentials.create` の代わりに `create` が提供されています。
117+
118+
.github/@webauthn-jsonを利用したクレデンシャルの作成
119+
[source,javascript,caption="例 {counter:number}: "]
120+
----
121+
import {
122+
create,
123+
parseCreationOptionsFromJSON,
124+
} from "@github/webauthn-json/browser-ponyfill";
125+
126+
const response = await fetch("<endpoint path that returns PublicKeyCredentialCreationOptions as JSON>") //fetch PublicKeyCredentialCreationOptions as JSON string
127+
const publicKeyCredentialCreationOptionsJSON = await response.json() // convert to JSONObject
128+
const credentialCreationOptions = parseCreationOptionsFromJSON(publicKeyCredentialCreationOptionsJSON); // convert to PublicKeyCredentialCreationOptions
129+
const publicKeyCredential = await create({ publicKey: credentialCreationOptions}); // create PublicKeyCredential
130+
const registrationResponseJSON = publicKeyCredential.toJSON() // JSON object of publicKeyCredential
131+
const registrationResponseJSONStr = JSON.stringify(registrationResponseJSON) // JSON string representation of publicKeyCredential
132+
----
133+
このpony-fillの `create` メソッドを利用して得られた publicKeyCredentialでは、 `toJSON` メソッドが利用可能です。
134+
135+
`PublicKeyCredential.parseRequestOptionsFromJSON` の代わりとしては、 `parseRequestOptionsFromJSON` が、
136+
`naviagator.credentials.get` の代わりに `get` が提供されています。
137+
138+
.github/@webauthn-jsonを利用したクレデンシャルの取得
139+
[source,javascript,caption="例 {counter:number}: "]
140+
----
141+
import {
142+
get,
143+
parseRequestOptionsFromJSON,
144+
} from "@github/webauthn-json/browser-ponyfill";
145+
146+
const response = await fetch("<endpoint path that returns PublicKeyCredentialRequestOptions as JSON>");
147+
const publicKeyCredentialRequestOptionsJSON = await response.json();
148+
const credentialGetOptions = parseRequestOptionsFromJSON(publicKeyCredentialRequestOptionsJSON);
149+
const publicKeyCredential = await get({ publicKey: credentialGetOptions});
150+
const authenticationResponseJSON = publicKeyCredential.toJSON()
151+
const authenticationResponseJSONStr = JSON.stringify(authenticationResponseJSON)
152+
----
110153

111154
// === 非同期サポート
112155
//

docs/src/reference/asciidoc/ja/quick-start.adoc

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,8 @@ WebAuthnの鍵ペアの生成において中心となるAPIは、ブラウザの
161161
HTMLページに埋め込んでも良いですし、チャレンジを返却するRESTエンドポイントを用意することも可能です。
162162
`navigator.credentials.create` メソッドのパラメータである、 `PublicKeyCredentialCreationOptions` 全体を返却するエンドポイントを用意するのも良いアイデアでしょう。
163163
WebAuthnのJava Script APIには、 `PublicKeyCredential.parseCreationOptionsFromJSON` というメソッドが用意されており、JSONとしてシリアライズされた `PublicKeyCredentialCreationOptions` をパースすることが可能です。
164+
但し、2024/12現在、Safariでは `PublicKeyCredential.parseCreationOptionsFromJSON` が利用できません。代替策については、<<./deep-dive.adoc#Safariで未サポートなJSON serialization APIsの代替,Safariで未サポートなJSON serialization APIsの代替>> を参照してください。
165+
164166
WebAuthn4Jは `PublicKeyCredentialCreationOptions` を表現するJavaのクラスを提供しており、バックエンドサーバー側でJSONを組み立てる際にご活用頂けます。
165167

166168
.`PublicKeyCredentialCreationOptions` 全体をREST Endpointから取得して `navigator.credentials.create` を呼出
@@ -182,6 +184,7 @@ const publicKeyCredential = await navigator.credentials.create({ publicKey: cred
182184
バックエンドサーバー側にどのようなフォーマットで送信するかについてもWebAuthn仕様では定義されていません。
183185
但し、WebAuthnクレデンシャルである `PublicKeyCredential` というJavaScriptの型には、 `toJSON` というメソッドが用意されており、
184186
こちらと `JSON.stringify` を利用してシリアライズしたデータを送信するのが一つのベストプラクティスです。
187+
但し、この `toJSON` メソッドもSafariでは利用できませんが、代替策については、<<./deep-dive.adoc#Safariで未サポートなJSON serialization APIsの代替,Safariで未サポートなJSON serialization APIsの代替>> を参照してください。
185188

186189
.`PublicKeyCredential` の送信
187190
[source,javascript,caption="例 {counter:number}: "]
@@ -258,7 +261,7 @@ save(credentialRecord); // please persist credentialRecord in your manner
258261
このジェスチャーには、生体認証に限らず、静電容量ボタンのタッチ等、当人認証が行われない操作も含まれます。
259262
WebAuthnにおいては、UPフラグは基本的に必須ですので `true` を指定すべきですが、パスワードからパスキーへの自動アップグレード時のクレデンシャル自動生成時のシナリオに限っては `false` となります。
260263

261-
b
264+
262265
サーバーの状態については、 `serverProperty` としてまとめています。
263266
`ServerProperty` のコンストラクタを呼び出す際のパラメータには以下の値を指定して下さい。
264267

@@ -278,7 +281,7 @@ WebAuthnでの認証時において中心となるAPIは、ブラウザの `navi
278281
認証のフローの図の通り、認証処理においても、まずバックエンドサーバー側でチャレンジを生成し、セッションに保存する一方、クライアントにチャレンジを引き渡す必要があります。
279282
`navigator.credentials.get` メソッドのパラメータにも `challenge` が存在するためです。
280283
バックエンドサーバーからフロントエンド(クライアント)への認証処理のチャレンジの受け渡し方法もWebAuthn仕様では定められていません。登録処理同様、お好みの方法でチャレンジをフロントエンド側に引き渡して下さい。
281-
`navigator.credentials.get` メソッドのパラメータである、 `PublicKeyCredentialGetOptions` をパースするJava Script APIは、 `PublicKeyCredential.parseCreationGetOptionsFromJSON` です。
284+
`navigator.credentials.get` メソッドのパラメータである、 `PublicKeyCredentialGetOptions` をパースするJava Script APIは、 `PublicKeyCredential.parseCreationGetOptionsFromJSON` です。 `PublicKeyCredential.parseCreationGetOptionsFromJSON` がSafariで利用できない問題の代替案は<<./deep-dive.adoc#Safariで未サポートなJSON serialization APIsの代替,Safariで未サポートなJSON serialization APIsの代替>> を参照してください。
282285
`navigator.credentials.get` メソッドに指定できるその他のオプションに関しては、 https://developer.mozilla.org/en-US/docs/Web/API/CredentialsContainer/get[MDN: CredentialsContainer: get() メソッド]を参照下さい。
283286

284287
.`PublicKeyCredentialGetOptions` 全体をREST Endpointから取得して `navigator.credentials.get` を呼出

0 commit comments

Comments
 (0)