aboutsummaryrefslogtreecommitdiff
path: root/server/_build/default/lib/jwt/src/jwk.erl
blob: 9226aae7d6999339886b65ce8afbc886d31c2b3f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
%% @doc RFC 7517: JSON Web Key (JWK)

-module(jwk).
-include_lib("public_key/include/OTP-PUB-KEY.hrl").

-export([encode/2, decode/2]).

-type id()         :: binary().
-type public_key() :: #'RSAPublicKey'{} | pem().
-type pem()        :: binary().
-type json()       :: binary().

-spec encode(id(), public_key()) -> {ok, json()} | {error, _}.
%% @doc encode Erlang/OTP Key to JWK
encode(Id, #'RSAPublicKey'{modulus = N, publicExponent = E}) ->
    {ok, jsx:encode(
        #{
            keys =>
            [
                #{
                    kid => Id,
                    kty => <<"RSA">>,
                    n   => encode_int(N),
                    e   => encode_int(E)
                }
            ]
        }
    )};
encode(Id, PEM) when is_binary(PEM) ->
    [RSAEntry] = public_key:pem_decode(PEM),
    encode(Id, public_key:pem_entry_decode(RSAEntry));
encode(_, _) ->
    {error, not_supported}.

-spec decode(id(), json()) -> {ok, public_key()} | {error, _}.
%% @doc decode JWK to Erlang/OTP Key
decode(Id, #{<<"keys">> := JWTs}) ->
    decode(
        lists:dropwhile(
            fun(X) ->
                maps:get(<<"kid">>, X, undefined) /= Id
            end,
            JWTs
        )
    );
decode(Id, Json) when is_binary(Json) ->
    decode(Id, jsx:decode(Json, [return_maps])).

%% @private
decode([#{<<"kty">> := <<"RSA">>, <<"n">> := N, <<"e">> := E} | _]) ->
    {ok,
        #'RSAPublicKey'{
            modulus        = decode_int(N),
            publicExponent = decode_int(E)
        }
    };
decode([]) ->
    {error, not_found};
decode(_) ->
    {error, not_supported}.


%% @private
encode_int(X) ->
    base64url:encode(binary:encode_unsigned(X)).

%% @private
decode_int(X) ->
    binary:decode_unsigned(base64url:decode(X)).