When integrating Sign in with Apple you generate a key in your apple developer account.
It's a file that is named like AuthKey_3JMD5K6.p8
and looks like
-----BEGIN PRIVATE KEY-----
MasdfjalskdasdflaASDFAadsflkjaADSFAewfljasdfljkasefasdflkjasdf
asdfljkasdfASDFASDFoiqretasdoiyjlfsbgREtaREGSDFBREtafsrgAREGfdsgaregR
LKJIOEWFNLasdflkawefjoiasdflk
-----END PRIVATE KEY-----
so I made a var appleKey := MasdfjalskdasdflaASDFAadsflkjaADSFAewfljasdfljkasefasdflkjasdf asdfljkasdfASDFASDFoiqretasdoiyjlfsbgREtaREGSDFBREtafsrgAREGfdsgaregRLKJIOEWFNLasdflkawefjoiasdflk
I've signed jwt with the HMAC-SHA method before which is fairly straightforward but I don't know how to sign a jwt with the ECDSA method.
I wrote my code the same way I did for the HMAC-SHA method but get an error key is of invalid type
So using the the jwt library for golang how can I sign my jwt with ECDSA method?
My code
// generate client secret jwt using apple key
expirationTime := time.Now().Add(5 * time.Minute)
claims := &Claims{
StandardClaims: jwt.StandardClaims {
Audience: "https://appleid.apple.com",
Subject: "com.app.ios",
Issuer: string(appleTeamId),
ExpiresAt: expirationTime.Unix(),
IssuedAt: time.Now().Unix(),
},
}
appleToken := jwt.NewWithClaims(jwt.SigningMethodES256, claims)
appleToken.Header["kid"] = appleKid
signedAppleToken, err := appleToken.SignedString(appleKey)
I now know this isn't how you do it and it's a little bit more complex than that but what is the way to do it?
I found this article that tells you how to manually do it:
http://p.agnihotry.com/post/validating_sign_in_with_apple_authorization_code/
But I'm already using the jwt library for golang for the other part of the token:
https://godoc.org/github.com/dgrijalva/jwt-go
In the github.com/dgrijalva/jwt-go
's SigningMethodECDSA.Sign docs you can find:
[...] For this signing method, key must be an
ecdsa.PrivateKey
struct
So, to put together an example:
p8bytes, err := ioutil.ReadFile("SomeAppleKey.p8")
if err != nil {
log.Println(err)
return
}
// Here you need to decode the Apple private key, which is in pem format
block, _ := pem.Decode(p8bytes)
// Check if it's a private key
if block == nil || block.Type != "PRIVATE KEY" {
log.Println("Failed to decode PEM block containing private key")
return
}
// Get the encoded bytes
x509Encoded := block.Bytes
token := jwt.NewWithClaims(
jwt.SigningMethodES256, // specific instance of `*SigningMethodECDSA`
jwt.StandardClaims{
// ...
},
)
// Now you need an instance of *ecdsa.PrivateKey
parsedKey, err := x509.ParsePKCS8PrivateKey(x509Encoded) // EDIT to x509Encoded from p8bytes
if err != nil {
panic(err)
}
ecdsaPrivateKey, ok := parsedKey.(*ecdsa.PrivateKey)
if !ok {
panic("not ecdsa private key")
}
// Finally sign the token with the value of type *ecdsa.PrivateKey
signed, err := token.SignedString(ecdsaPrivateKey)
if err != nil {
panic(err)
}
fmt.Println(signed) // the signed JWT
Note: as shown in the code snippet, because the key file from Apple is in PEM format, it needs to be decoded first
Please be aware that github.com/dgrijalva/jwt-go
has been unmaintained for a long time and has critical unfixed bugs. And doesn't support Go modules, before the version 4 (which is just a preview anyway). I strongly recommend to choose an different library for dealing with JWT.
There is now an official community fork of the library: golang-jwt/jwt
blessed by the owner of the original project.