# \[ANN\] WebAuthn.jl

**URL:** https://discourse.julialang.org/t/ann-webauthn-jl/132672
**Category:** Package Announcements
**Created:** [September 26, 2025, 10:15am UTC](https://discourse.julialang.org/t/ann-webauthn-jl/132672 "2025-09-26T10:15:48Z")
**Posts on this page:** 10
**Page:** 1

<div class="post-metadata">

### Author: ![andreeco](https://avatars.discourse-cdn.com/v4/letter/a/d26b3c/32.png) [@andreeco](https://discourse.julialang.org/u/andreeco)
#### Post date: [September 26, 2025, 10:15am UTC](https://discourse.julialang.org/t/ann-webauthn-jl/132672/1 "2025-09-26T10:15:48Z")

</div>

Hi,

I’m happy to announce **WebAuthn.jl** , a Julia package for [W3C WebAuthn](https://www.w3.org/TR/webauthn/) and modern passwordless authentication using passkeys and security keys.

WebAuthn.jl brings end-to-end functions for registration and login, CBOR/COSE key parsing, secure challenge generation, signature verification, and PEM export—making it straightforward to integrate passkey or FIDO2/U2F flows into Julia web servers or applications without any required web framework.

## Features

- CBOR/COSE key parsing (P-256/ES256, RSA/RS256, Ed25519)
- Base64url encoding/decoding & random challenge generator
- Registration and authentication option builders (browser-ready)
- Secure signature and challenge verification (OpenSSL/Sodium-backed)
- PEM export for downstream tools or libraries
- Fully framework-agnostic code (works with _any_ HTTP/Socket tool)

## How WebAuthn Works

WebAuthn enables **passwordless** , phishing-resistant login using public-key cryptography.  
A user’s device generates and stores a private credential (passkey); the private key never leaves the device or browser.

 ![webauthn_registration](https://global.discourse-cdn.com/julialang/original/3X/7/3/73e8d2d35ab46244bbf42ceb12701b7782685441.svg)  
 ![webauthn_authentication](https://global.discourse-cdn.com/julialang/original/3X/6/f/6fd0d0cd8e72202efb42ed8fb0b9d164fcdc1aee.svg)

## Demo & Workflow

Here are a few screenshots from the included minimal server and client example (HTML/JS assets provided in the source code):

For the full example look here.

You can **test WebAuthn** with a physical security key, or (in Chrome) via your smartphone over Bluetooth:

- Insert a hardware device and register.
- Or, scan a QR code with your phone to use it as a “virtual” security key.

 ![register](https://global.discourse-cdn.com/julialang/original/3X/a/1/a185b5b54bedbdae801aee2e5b4b38279fe8700a.png)  
 ![success](https://global.discourse-cdn.com/julialang/original/3X/e/a/ea9b3a926dce345f26e5f1a74e29684bb485fb8f.png)  
 ![qr_code_chrome](https://global.discourse-cdn.com/julialang/original/3X/c/4/c44e4b4e59356aca5efff02a12f44212dab6410c.png)

## Documentation & Contributions

- 📖 [API docs](https://andreeco.github.io/WebAuthn.jl/dev/)
- 🛠 [GitHub source & issue tracker](https://github.com/andreeco/WebAuthn.jl)
- Contributions and feedback are very welcome!

_P.S. This also serves as the foundation for a third-party AuthPlugin for GenieFramework, which I hope to publish in the future._

Please try it out and give feedback!

---

<div class="post-metadata">

### Author: ![foobar\_lv2](https://avatars.discourse-cdn.com/v4/letter/f/ee59a6/32.png) [@foobar\_lv2](https://discourse.julialang.org/u/foobar_lv2)
#### Post date: [September 26, 2025, 8:15pm UTC](https://discourse.julialang.org/t/ann-webauthn-jl/132672/2 "2025-09-26T20:15:52Z")

</div>

Are you a human, @andreeco ?

Did you use an LLM in the creation of this package?

If you are indeed a human, could you talk with us a little about who you are, how you created this package, and about the thought processes that led you to believe that this is a good idea?

* * *

For other people seeing this conversation, take a look at the linked github. Look at [WebAuthn.jl/src/signature.jl at 87bce0746901b07ebb1a6b361c0d165c6c150d8d · andreeco/WebAuthn.jl · GitHub](https://github.com/andreeco/WebAuthn.jl/blob/87bce0746901b07ebb1a6b361c0d165c6c150d8d/src/signature.jl#L65) and the code for “parsing” ans1/der [WebAuthn.jl/src/cose\_keys.jl at 87bce0746901b07ebb1a6b361c0d165c6c150d8d · andreeco/WebAuthn.jl · GitHub](https://github.com/andreeco/WebAuthn.jl/blob/87bce0746901b07ebb1a6b361c0d165c6c150d8d/src/cose_keys.jl#L441)

* * *

If you concur, @mbauman , I’d ask you to not completely delete this thread outright, but rather rename and move to #Meta Discussion – I think there is an important conversation to be had; either with @andreeco if he turns out to be a well-intentioned human, or within ourselves if this turns out to be spam / slop / a supply chain attack.

---

<div class="post-metadata">

### Author: ![andreeco](https://avatars.discourse-cdn.com/v4/letter/a/d26b3c/32.png) [@andreeco](https://discourse.julialang.org/u/andreeco)
#### Post date: [September 26, 2025, 9:34pm UTC](https://discourse.julialang.org/t/ann-webauthn-jl/132672/3 "2025-09-26T21:34:45Z")

</div>

Hi foobar\_lv2,

I will explain a bit and you will see I’m human. Recently I had to switch from [MbedTLS](https://github.com/andreeco/WebAuthn.jl/blob/87bce0746901b07ebb1a6b361c0d165c6c150d8d/src/signature.jl#L65) to OpenSSL since I read that MbedTLS had security issues and it’s maybe discontinued. (See the Slack channel for the Binary Builder and my posts there.) When you look [here](https://github.com/andreeco/WebAuthn.jl/blob/87bce0746901b07ebb1a6b361c0d165c6c150d8d/src/signature.jl#L104) you will understand line 65 also. I primarily had a lot of troubles with `verify_webauthn_signature` which is why the function in line 105 was originally used. But the Avoid this too? Line 65 is there because I think it’s better to use multiple dispatch with OKPPublicKey, RSAPublicKey… The basic issue might have been that I had troubles with verification because I did not hash properly before verification? The conversions (pem, der) are there because of my attempts to solve the verification properly.

In the Binary Builder Channel you will also see that I faced issues building tarballs for libfido2, which would be also reasonable for WebAuthn.

[This](https://github.com/andreeco/WebAuthn.jl/blob/87bce0746901b07ebb1a6b361c0d165c6c150d8d/src/cose_keys.jl#L441) was done when I asked an LLM how to break functions into smaller parts so that they are not too long. This is also when asn1\_parse\_length became its own function.

I did use an LLM for creation of the package in a structured way and I especially tried to meet as much of the specs of WebAuthn as possible as you will see in the tests. But I think that’s good? I found out for example that CBOR.jl does not meet the specs and should error at a certain point.

I currently try to implement a PaymentsPlugin for GenieFramework. For this I first need a secure user management. When I did this I created the packages OneTimePasswords and WebAuthn so other non non-Genie frameworks can also benefit from it.

I will pass some screenshots from what I develop and where this WebAuthn originated from.

 ![Screenshot From 2025-09-26 23-11-07](https://global.discourse-cdn.com/julialang/original/3X/9/7/9786b0019f176c71cc760a70ec732cccb281c7e1.png)  
 ![Screenshot From 2025-09-26 23-10-47](https://global.discourse-cdn.com/julialang/original/3X/c/b/cb770b0a14ec5974794eb952d12a2c8f6c6a7760.png)  
 ![Screenshot From 2025-09-26 23-09-13](https://global.discourse-cdn.com/julialang/original/3X/7/8/789cec1e3fc324615cb480a1a5c9d4721156af8f.png)  
 ![Screenshot From 2025-09-26 23-09-00](https://global.discourse-cdn.com/julialang/original/3X/0/2/02e8f951e7899fc3b5402b96cce5940c824948d7.png)  
 ![Screenshot From 2025-09-26 23-07-27](https://global.discourse-cdn.com/julialang/original/3X/e/3/e36e7ee6d7a229558456fa0705e78fe7f7231d6b.png)  
 ![Screenshot From 2025-09-26 23-12-04](https://global.discourse-cdn.com/julialang/original/3X/f/5/f5d5687eceb99f7eef52af5c4172ffd5cf7bd136.png)  
 ![Screenshot From 2025-09-26 23-12-00](https://global.discourse-cdn.com/julialang/original/3X/1/f/1fc26a3affb2fa0eb828d8e9d6b5b66d58360201.png)  
 ![Screenshot From 2025-09-26 23-11-37](https://global.discourse-cdn.com/julialang/original/3X/6/4/6412da71fff126c5be0e1547630259cb7e33ef2a.png)  
 ![Screenshot From 2025-09-26 23-18-19](https://global.discourse-cdn.com/julialang/original/3X/e/c/ec94f9bb8a39df9c3359238d14429b2090f44d32.png)  
 ![Screenshot From 2025-09-26 23-20-44](https://global.discourse-cdn.com/julialang/original/3X/5/a/5ae68dcc3400393f157e04e6871ec3d70d499fd4.png)

To my background I did study economics and learned Julia some years ago after my master thesis in econometrics using R. I wanted to learn Python but before deciding I thought that it would be wise to check first what is the best language for me. I saw that BlackRock uses Julia for Alladin and NASA also. Then I learned Julia by reading the documentation over and over again. I use Julia for economical simulations in my job.

But more important: Is there a issue with the quality of my code in the sense of security?

---

<div class="post-metadata">

### Author: ![goerz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/goerz/32/3269_2.png) [@goerz](https://discourse.julialang.org/u/goerz)
#### Post date: [September 26, 2025, 9:36pm UTC](https://discourse.julialang.org/t/ann-webauthn-jl/132672/4 "2025-09-26T21:36:45Z")

</div>

> [@foobar\_lv2](#):
>
> the thought processes that led you to believe that this is a good idea?

If you have concerns, you may want to leave a blocking comment on the registration at [New package: WebAuthn v0.1.0 by JuliaRegistrator · Pull Request #139195 · JuliaRegistries/General · GitHub](https://github.com/JuliaRegistries/General/pull/139195)

There is no rule that LLMs cannot be used for the development for Julia packages, but the submitting author has to take the responsibility for whatever is being submitted. What is definitely not okay is to let an LLM generate a package and then submit it without detailed human review. If you think that is what is going on here, or if you think the package has some other major problem (whether it’s LLM-generated or not), you should block the registration until the issue is resolved.

> [@foobar\_lv2](#):
>
> For other people seeing this conversation, take a look at the linked github. Look at [WebAuthn.jl/src/signature.jl at 87bce0746901b07ebb1a6b361c0d165c6c150d8d · andreeco/WebAuthn.jl · GitHub](https://github.com/andreeco/WebAuthn.jl/blob/87bce0746901b07ebb1a6b361c0d165c6c150d8d/src/signature.jl#L65) and the code for “parsing” ans1/der [WebAuthn.jl/src/cose\_keys.jl at 87bce0746901b07ebb1a6b361c0d165c6c150d8d · andreeco/WebAuthn.jl · GitHub](https://github.com/andreeco/WebAuthn.jl/blob/87bce0746901b07ebb1a6b361c0d165c6c150d8d/src/cose_keys.jl#L441)

it’s not obvious to me what is wrong with the code at those links.

---

<div class="post-metadata">

### Author: ![foobar\_lv2](https://avatars.discourse-cdn.com/v4/letter/f/ee59a6/32.png) [@foobar\_lv2](https://discourse.julialang.org/u/foobar_lv2)
#### Post date: [September 26, 2025, 10:19pm UTC](https://discourse.julialang.org/t/ann-webauthn-jl/132672/5 "2025-09-26T22:19:05Z")

</div>

Apologies for assuming you were AI.

Then we can have a productive conversation about security / code quality instead of a conversation about spam removal, yay!

No offense to you @andreeco – I think you don’t have ambitions to write security-critical code, and you currently should not publish security-critical code for others, and you’re currently not qualified to review security-critical code that has come out of an LLM.

You should wrap an established package. Using openssl / sodium instead of writing your own crypto is a good start, but the remaining complexity – asn1/der parsing, etc – is clearly not what you should do yourself.

> [@goerz](#):
>
> it’s not obvious to me what is wrong with the code at those links.

The asn1/der “parsing” code does not parse. You should not write your own “parser” for that, just like you do not write your own crypto. Above link searches a binary blob for a 0x03 byte and checks whether that could be the start of a BITSTRING.

This is the same category error as using a regular expression to parse HTML, in an explicitly security-critical package.

The correct answer when encountering that is to take the person aside, immediately ensure that they will pause publishing security-critical code, review/yank all security-critical code they ever touched, and then once all fires are taken out, explain them the issue.

This is not necessarily an issue of knowledge, but rather an issue of people not respecting the limits of their own knowledge and how irresponsible it is to spread wrong security-critical code in the ecosystem.

There is an internet classic for the regex / html thing

> <https://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags>

---

<div class="post-metadata">

### Author: ![andreeco](https://avatars.discourse-cdn.com/v4/letter/a/d26b3c/32.png) [@andreeco](https://discourse.julialang.org/u/andreeco)
#### Post date: [September 26, 2025, 11:54pm UTC](https://discourse.julialang.org/t/ann-webauthn-jl/132672/6 "2025-09-26T23:54:50Z")

</div>

> [@foobar\_lv2](#):
>
> You should wrap an established package.

I do absolutely agree and that is what I thought I did. All verifications go through either Sodium, OpenSSL (and previous MbedTLS).

My goal was not to write a crypto library.

The issue with `find_bitstring`, `asn1_parse_length` … happened because OpenSSL\_jll is not build with ossl-modules and MbedTLS seems to be insecure in Julia at the moment. I stopped the register myself until this is solved. Help is wanted!

But I think there is also a place where normal users should be able to look up which algorithms are secure and use them via a proven library.

---

<div class="post-metadata">

### Author: ![Janis\_Erdmanis](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/janis_erdmanis/32/10869_2.png) [@Janis\_Erdmanis](https://discourse.julialang.org/u/Janis_Erdmanis)
#### Post date: [September 27, 2025, 6:55pm UTC](https://discourse.julialang.org/t/ann-webauthn-jl/132672/7 "2025-09-27T18:55:26Z")

</div>

I disagree with the sentiment that one should not attempt to implement their own crypto, even if the person does not have prior experience in doing so. This is how we attract experienced cryptography professionals to the Julia community by growing them ourselves. The only thing that matters is the enthusiasm and willingness to learn as one goes and put that into practice.

Regarding code, testing had been done somewhat systematically. In addition, using `OpenSSL_jll` and `Sodium` is a good practice, as it leverages existing cryptographic implementations. The code appears to be primarily focused on piping data in and out for thoose implementations.

However, I agree that the chosen way to implement parsing really sucks. It is not possible in your case to take the parser apart and test it separately with test vectors, it is dependent on what is being parsed. A thorn in the eye for me is the `cose_keys.jl` file with the `find_bitstring` function. This is lazy!

To improve things, you should implement a DER parser. This is much easier to do in a memory-safe language like Julia. If I were to do it myself, I would create an isolated module like:

```julia-auto

module DER

struct DERTree
# internals for the tree representation
end

function decode(::Vector{UInt8})::DERTree end

function encode(::DERTree)::Vector{UInt8} end

function decode_pem(::String)::DERTree end

function encode_pem(::DERTree)::String end

end

```

Once you have this module, find the test vectors with which you can test the DER implementation.

Then refactor the rest of your code, which would introduce a new pattern in verification, something like (just as an example):

```julia-auto
tree = decode(payload)

if tree[1] == “RSA”
    # some other parsing
elseif tree[1] == “EC2”
    x, y = tree[2]
else
    error(“Can’t parse”)
end

```

Since you have already figured out how to use OpenSSL\_jll and Sodium, you can also implement the parser with LLM, bringing a helping hand. Good luck!

---

<div class="post-metadata">

### Author: ![andreeco](https://avatars.discourse-cdn.com/v4/letter/a/d26b3c/32.png) [@andreeco](https://discourse.julialang.org/u/andreeco)
#### Post date: [September 28, 2025, 6:51am UTC](https://discourse.julialang.org/t/ann-webauthn-jl/132672/8 "2025-09-28T06:51:00Z")

</div>

Thanks for your reply. I read some of your [code](https://github.com/PeaceFounder) while working on this package!

If I parse it myself I would still call into a language that is not [memory-safe](https://letsencrypt.org/docs/a-warm-welcome-to-asn1-and-der/#safety) for verification.

I’m about to wrap [Webauthn-rs](https://github.com/kanidm/webauthn-rs), which seems to be WebAuthn Level 3 compliant and security audited.

---

<div class="post-metadata">

### Author: ![Janis\_Erdmanis](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/janis_erdmanis/32/10869_2.png) [@Janis\_Erdmanis](https://discourse.julialang.org/u/Janis_Erdmanis)
#### Post date: [September 28, 2025, 7:41am UTC](https://discourse.julialang.org/t/ann-webauthn-jl/132672/9 "2025-09-28T07:41:36Z")

</div>

> [@andreeco](#):
>
> If I parse it myself I would still call into a language that is not [memory-safe](https://letsencrypt.org/docs/a-warm-welcome-to-asn1-and-der/#safety) for verification.

IMO the `signatures.jl` file where you interface the `OpenSSL_jll` and `Sodium.jl` is not that bad. Writing DER parser is also not that hard in a memory safe language if you don’t need top performance.

> [@andreeco](#):
>
> I’m about to wrap [Webauthn-rs](https://github.com/kanidm/webauthn-rs), which seems to be WebAuthn Level 3 compliant and security audited.

If you can get it wrapped, go for it!

---

<div class="post-metadata">

### Author: ![andreeco](https://avatars.discourse-cdn.com/v4/letter/a/d26b3c/32.png) [@andreeco](https://discourse.julialang.org/u/andreeco)
#### Post date: [October 2, 2025, 11:36am UTC](https://discourse.julialang.org/t/ann-webauthn-jl/132672/10 "2025-10-02T11:36:32Z")

</div>

I fixed a lot of issues, and anyone who wants to look into the source code can do so. It’s marked as **Experimental** , and I don’t plan to register it soon, but I really appreciate any feedback.

There is some redundant logic, mostly from the way the code was restructured, but it’s ok (for now).

Wrapping `Webauthn-rs` does not make sense since it has no C ABI.

> **[GitHub - andreeco/WebAuthn.jl](https://github.com/andreeco/WebAuthn.jl)**
>
> Contribute to andreeco/WebAuthn.jl development by creating an account on GitHub.
