Postgrest: JWT Asymmetric Keys Setup

Created on 5 Oct 2018  路  7Comments  路  Source: PostgREST/postgrest

Hi,

I am trying to setup Postgrest to use JWT's authenticating via Keycloak but am struggling with where I put the client secret.

If I use jwt.io and select RS256 then enter my public keycloak cert and my private key I can verify tokens that have been generated by keycloak, including checking they have the correct roles for postgrest.

What I am unsure of is how do i convert the public key certificate and client secret I have from there (which work with jwt.io) to be a client_secret in postgrest.

I have managed to generate a JWT with just the public cert in the following format:
{"alg":"RS256","e":"AQAB","kid":"lK2dtP5SJCAzhrYjBBE7VecNsCbK59LiOYF5ch-Pmuo","kty":"RSA","n":"xxxxx","use":"sig"}

I note that is has "use" and not "key_ops" - it does not seem to make any difference if i manually add that. But it does not include the secret and thus postgrest fails and calls with 401 {"message":"JWSError JWSInvalidSignature"}

Thanks

Mark

Most helpful comment

I should note to get the key, I take the RS256 key from 'Realm Settings -> Master -> Keys -> active' selecting the RS256 Certificate key. This I then put into a file wrapping with the lines -----BEGIN CERTIFICATE----- / -----END CERTIFICATE-----.
After that I then run 'openssl x509 -in cert.pem -pubkey -noout' to generate the key in the correct format.

All 7 comments

Hm.. did you escaped the quotes on the jwt-secret like {\"alg\": .. }? Check http://postgrest.org/en/v5.1/auth.html#asym-keys

Also you could try specifying the jwt-secret as a file, like jwt-secret = "@rsa.jwk.pub".

@pixie79 Did you managed to solve this?

Hi Steve,

Yes I did following advise from Russel.

  1. Generate a JWK for postgrest:
    In Keycloak admin console, go to Realm Settings -> Keys and create a JWK from the RSA public key. You can use this tool https://russelldavies.github.io/jwk-creator but make sure you wrap it in:
    -----BEGIN PUBLIC KEY-----
    ...
    -----END PUBLIC KEY-----

In postgrest.conf add the JWK (making sure you escape it), e.g:
jwt-secret = "{ \"kty\": \"RSA\", \"n\": \"5bakJ-pSt99z3RcdGWi0Xmb6F8hIjDSWU5xCTC0bQ1F-KQ9yusTz-nevkzp6MnuRiO2P9-_vqbpdh6XXbWh94KJdFk8SCP3DocCDx0rY3b4bhK-KuF9CM5jA1XeNxekeZYjrynmGCTFUD6ewGlXupNUke_LcKMhQVzxFsOmAAGmM0604hoBpxXmwhf-594MtpGwDRgKf_4y15leSmW-_B7UImH3jED9WZkiBZM2y2jdbrfb9XsKb2xzPPoqWNTE9XMewmesQCi0CyMNBxyJyuUxNbQmcLQUNUZ_CNWZcaRqAGfFBkuWBb_G51dBZrU4Qtcb4ZRkTSoRbEWUbfrh_8w\", \"e\": \"AQAB\" }"

  1. Create a client with public access type. Add the name to postgrest.conf, e.g: jwt-aud = "myClient"

  2. Create a client mapper for the postgrest role (remember the JWT your client sends postgrest must have a "role" key otherwise it switches to anonymous mode). For testing you can create a hardcoded claim and later switch to using a user attribute or something. So if you create a hardcoded claim of "admin" then make sure that there is a corresponding PostgreSQL user called that which has access to what you're requesting.

For testing can get a JWT like so:
curl -s -d "client_id=myClient" -d "username=user" -d "password=pass" -d "grant_type=password" "$KEYCLOAK_SERVER/auth/realms/myRealm/protocol/openid-connect/token"
(be sure to replace values with a valid realm user). The JWT will be in the "access_token" key which you can use in your Authorization header of the request to postgrest. But it only lasts for 5 minutes so be quick or increase the expiry time.

Mark

I should note to get the key, I take the RS256 key from 'Realm Settings -> Master -> Keys -> active' selecting the RS256 Certificate key. This I then put into a file wrapping with the lines -----BEGIN CERTIFICATE----- / -----END CERTIFICATE-----.
After that I then run 'openssl x509 -in cert.pem -pubkey -noout' to generate the key in the correct format.

I want to add another comment here. I am using keycloak-angular and had big trouble getting this to work. All the steps in here are correct, but Angular sends Authorization: bearer instead of Authorization: Bearer by default. This can be fixed by using keycloak.init({bearerPrefix: 'Bearer'}) in your initializer for the library. Took my ages to figure out.

Here is an example one liner that get the key in the correct format.

curl https://KEYCLOAK_URL/auth/realms/REALM_NAME/protocol/openid-connect/certs | jq -rc '.keys | first | {kid, kty, alg, n, e}'

Was this page helpful?
0 / 5 - 0 ratings

Related issues

posix4e picture posix4e  路  34Comments

eric-brechemier picture eric-brechemier  路  27Comments

LorenzHenk picture LorenzHenk  路  23Comments

dudleycarr picture dudleycarr  路  25Comments

RB14 picture RB14  路  32Comments