Если информация была полезной для вас, вы можете поблагодарить за труды Яндекс деньгами: 41001164449086 или пластиковой картой:

Переписываем JWKS c PHP на GoLang, openssl_pkey_get_details

Не так давно по работе появилась необходимость переписать проект c PHP на GoLang. Одной из подзадач стало написание хендлера обслуживающего JWKS endpoint. И если для PHP всё было  просто и понятно, то для Go пришлось повозиться.

Рассусоливать смысла не вижу, по этому далее приведу примеры кода хендлеров как они могли бы выглядеть. Разумеется в реальности они выглядят сложнее.

Итак,  на PHP:

use Lcobucci\JWT\Parsing\Encoder;

    public function handle(ServerRequestInterface $request): ResponseInterface
    {
        $publicKey = openssl_pkey_get_public(file_get_contents(getcwd() . '/data/public.key'));
        $details = openssl_pkey_get_details($publicKey);
        $encoder = new Encoder();
        return new JsonResponse([
            'keys' => [
                [
                    'kty' => 'RSA',
                    'e'   => $encoder->base64UrlEncode($details['rsa']['e']),
                    'kid' => 'rsa1',
                    'alg' => 'RS256',
                    'n'   => $encoder->base64UrlEncode($details['rsa']['n']),
                    'use' => 'sig',
                ],
            ],
        ]);
    }

И тоже самое на Golang

type JWKSStruct struct {
    Keys []JWKSStructKey `json:"keys"`
}

type JWKSStructKey struct {
    Kty string `json:"kty"`
    E   string `json:"e"`
    Kid string `json:"kid"`
    Alg string `json:"alg"`
    N   string `json:"n"`
    Use string `json:"use"`
}

func JWKS(responseWriter http.ResponseWriter, request *http.Request, publicKey *rsa.PublicKey) {
    if request.Method != http.MethodGet {
        http.Error(responseWriter, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
        return
    }

    responseWriter.Header().Set("Content-Type", "application/json; charset=utf-8")

    eBytes := make([]byte, 4, 4)
    binary.LittleEndian.PutUint32(eBytes, uint32(publicKey.E))

    key := JWKSStructKey{
        Kty: "RSA",
        E:   base64.RawURLEncoding.EncodeToString(eBytes[:3]),
        Kid: "rsa1",
        Alg: "RS256",
        N:   base64.RawURLEncoding.EncodeToString(publicKey.N.Bytes()),
        Use: "sig",
    }
    err := json.NewEncoder(responseWriter).Encode(JWKSStruct{Keys: []JWKSStructKey{key}})
    if err != nil {
        http.Error(responseWriter, err.Error(), http.StatusInternalServerError)
    }
}

На выходе получаем один и тот же JSON ответ.
С стандартом можно познакомиться, например здесь: tools.ietf.org/html/rfc7518
Надеюсь кому-то поможет.

Добавить комментарий


Если информация была полезной для вас, вы можете поблагодарить за труды Яндекс деньгами: 41001164449086 или пластиковой картой: