This story on HackerNoon has a decentralized backup on Sia.
Transaction ID: AhHZ6lqG5kbGsp6yI_bBHDehqh4JHhUvz714n3r8Xfc
Cover

How to Access Your YubiKey in Go on Windows

Written by @pheonix-k3ep8 | Published on 2026/1/19

TL;DR
Programmatic access lets you integrate YubiKeys directly into a Go application on Windows. On Windows, `piv.Cards()` uses the built-in WinSCard API to detect connected smart card devices.

YubiKeys are fantastic for securing authentication and cryptography, but integrating them directly into a Go application on Windows takes a few extra steps. In this article, we’ll walk through accessing a YubiKey in Go on Windows, step by step.

Installing piv-go

Install the piv-go module:

go get github.com/go-piv/piv-go/piv

Listing Connected YubiKeys on Windows

The following Go code will show you all the YubiKeys connected to your machine:

package main

import (
    "fmt"
    "github.com/go-piv/piv-go/piv"
)

func main() {
    cards, err := piv.Cards()
    if err != nil {
        panic(err)
    }

    if len(cards) == 0 {
        fmt.Println("No YubiKeys detected")
        return
    }

    for _, card := range cards {
        fmt.Println("Found YubiKey:", card)
    }
}

Accessing a PIV Slot on Windows

This Go program detects a connected YubiKey (PIV smart card) on Windows, opens it via piv-go, and reads the certificate from the PIV Authentication slot. It then prints the certificate’s subject details.

package main

import (
    "crypto/x509"
    "fmt"
    "github.com/go-piv/piv-go/piv"
)

func main() {
    cards, err := piv.Cards()
    if err != nil || len(cards) == 0 {
        panic("No YubiKeys detected")
    }

    yk, err := piv.Open(cards[0])
    if err != nil {
        panic(err)
    }
    defer yk.Close()

    cert, err := yk.Certificate(piv.SlotAuthentication)
    if err != nil {
        panic(err)
    }

    fmt.Println("Certificate Subject:", cert.Subject)
}

Signing Data on Windows

This Go program opens a connected YubiKey PIV device on Windows, retrieves the private key from the PIV Authentication slot, and uses it to sign a SHA-256 digest of some data. It then prints the resulting signature in hex.

package main

import (
    "crypto"
    "crypto/rand"
    "fmt"
    "github.com/go-piv/piv-go/piv"
)

func main() {
    cards, err := piv.Cards()
    if err != nil || len(cards) == 0 {
        panic("No YubiKeys detected")
    }

    yk, err := piv.Open(cards[0])
    if err != nil {
        panic(err)
    }
    defer yk.Close()

    key, err := yk.PrivateKey(piv.SlotAuthentication, nil)
    if err != nil {
        panic(err)
    }

    data := []byte("Hello, secure Windows world!")
    hash := crypto.SHA256.New()
    hash.Write(data)
    digest := hash.Sum(nil)

    signature, err := key.(crypto.Signer).Sign(rand.Reader, digest, crypto.SHA256)
    if err != nil {
        panic(err)
    }

    fmt.Printf("Signed data: %x\n", signature)
}

Wrapping Up

On Windows, piv-go leverages native WinSCard APIs to access YubiKeys, making it straightforward to use PIV slots and sign data. Programmatic access keeps your private keys secure and opens doors for custom authentication workflows on Windows systems.

[story continues]


Written by
@pheonix-k3ep8
Technical Writer on HackerNoon.

Topics and
tags
golang-security|yubikey-go-integration|yubikey-piv-go|piv-go-windows|hardware-security-keys-go|go-smart-card-windows|yubikey-signing-go|secure-authentication-go
This story on HackerNoon has a decentralized backup on Sia.
Transaction ID: AhHZ6lqG5kbGsp6yI_bBHDehqh4JHhUvz714n3r8Xfc