graphile / crystal

🔮 Graphile's Crystal Monorepo; home to Grafast, PostGraphile, pg-introspection, pg-sql2 and much more!
https://graphile.org/
Other
12.63k stars 572 forks source link

Unrecognized configuration parameter "jwt.claims.person_id" #353

Closed zorec closed 7 years ago

zorec commented 7 years ago

I encountered the error when I was going through the step by step tutorial. It occurs during the execution of this function forum_example.current_person() in PostgreSQL:

select forum_example.current_person();

ERROR: unrecognized configuration parameter "jwt.claims.person_id" CONTEXT: SQL function "current_person" during startup

In the GraphiQL, the current user query fails despite the successful authentication:

mutation authenticate($credentials:AuthenticateInput!) {
  authenticate(input:$credentials) {
    jwtToken { role personId }
    query {
      currentPerson { firstName }
    }
  }
}
{
  "credentials": {
    "email": "spowell0@noaa.gov",
    "password": "iFbWWlc"
  }
}

The following result is returned:

{
  "data": {
    "authenticate": {
      "jwtToken": {
        "role": "forum_example_person",
        "personId": 1
      },
      "query": {
        "currentPerson": null
      }
    }
  },
  "errors": [
    {
      "message": "unrecognized configuration parameter \"jwt.claims.person_id\"",
      "locations": [
        {
          "line": 5,
          "column": 7
        }
      ],
      "path": [
        "authenticate",
        "query",
        "currentPerson"
      ]
    }
  ]
}

Afterward, I cloned the forum example from the repository to check that I didn't make a mistake. There was another error when enabling row-level security in schema.sql:

alter table pis.person enable row level security;

ERROR: syntax error at or near "row" However, I commented out these commands (from line 206) because it shouldn't be relevant, it is the last step of the tutorial.

Finally, here are the details about my environment: OS: Ubuntu 16.04.1 LTS

psql --version
postgraphql --version

psql (PostgreSQL) 9.6.2 2.6.0

benjie commented 7 years ago

The documentation suggests that alter table X enable row level security; should work on Postgres 9.5+; your client is for 9.6.2 but what is the version of the server you are connecting to?

https://www.postgresql.org/docs/9.6/static/ddl-rowsecurity.html

As for the unrecognised configuration parameter, that's probably from calling current_setting(...) for a field that doesn't exist; you should be able to fix that with alter database DATABASE_NAME set "jwt.claims.person_id" to '';

calebmer commented 7 years ago

In order for:

select forum_example.current_person();

to work, and therefore:

{
  currentPerson { id }
}

as well, you will need to pass the JWT token you get (when --token forum_example.jwt_token is set) as an Authorization header to PostGraphQL 😊

This will effectively run:

set local jwt.claims.person_id to 'your_id';

In the database which will enable the forum_example.current_person procedure to work 👍

Make sure to run the SET command manually yourself if you want to test in the database.

zorec commented 7 years ago

@benjie You are right. My Postgres server version (9.4.8) has no support for row-level security.

Setting the default key works with an integer (empty string causes invalid input syntax for integer), but the default is only for users without a token. I assumed that the value will be (automatically) set after a user authenticated at least in GraphiQL. That is not true based on the requests, then I will add Authorization header by myself. Thanks for the help.

dfmarulanda commented 6 years ago

I'm having this problem. When asking for the jwt.claims.person_id im getting null always. I'm using postgres 10.

benjie commented 6 years ago

What command line/library options are you using? And is it this issue (where an error is thrown), or is it just that your values are coming back null? (Maybe you haven’t set a JWT secret?)

dfmarulanda commented 6 years ago

I'm using express + postgraphile (PG10) + nuxt.

const postgraphileOptions = {
  pgDefaultRole: 'crw_anonymous_swapper',
  graphiql: true,
  enableCors: true,
  jwtSecret: 'crowdswapper_master$$$',
  jwtPgTypeIdentifier: 'crw_public.jwt_token',
};

Everything works fine, I'm getting the role and the permissions works. But, when i try to retrieve the user id from the jwttoken, is returning always null. (this happens also when i'm running postgraphile standalone version)

create or replace function crw_public.current_swapper_id() returns INTEGER as $$
  select current_setting('jwt.claims.swapper_id', true)
$$ language sql stable;

the response always is:

{
  "data": {
    "authenticate": {
      "jwtToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiY3J3X3B1YmxpY19zd2FwcGVyIiwic3dhcHBlcl9pZCI6MjIsImlhdCI6MTUzNTA2NDMxNiwiZXhwIjoxNTM1MTUwNzE2LCJhdWQiOiJwb3N0Z3JhcGhpbGUiLCJpc3MiOiJwb3N0Z3JhcGhpbGUifQ.VTpxqYl_OdooINSwNWyi-BfzammP5cKpFTcOG9_vtiU",
      "query": {
        "currentSwapperId": null
      }
    }
  }
}
benjie commented 6 years ago

Ohhhhh! If you use the JWT in the header and run the query again it should work. To make it work as you have there (in the same request with which you fetch the JWT) you need to call set_config(‘jwt.claims.person_id’, ..., true) in your authenticate function.

dfmarulanda commented 6 years ago

Yeah. But, even with the JWT in the header as

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiY3J3X3B1YmxpY19zd2FwcGVyIiwic3dhcHBlcl9pZCI6MjIsImlhdCI6MTUzNTA2NDMxNiwiZXhwIjoxNTM1MTUwNzE2LCJhdWQiOiJwb3N0Z3JhcGhpbGUiLCJpc3MiOiJwb3N0Z3JhcGhpbGUifQ.VTpxqYl_OdooINSwNWyi-BfzammP5cKpFTcOG9_vtiU

is returning null.

sjmcdowall commented 6 years ago

Ah -- isn't the header supposed to be

Authorization Bearer XXXXXXX ???

Not Authenticate??

I've never used anything but Authorization (or authorization of course -- case doesn't matter)

On Aug 23, 2018, at 6:55 PM, Daniel Marulanda notifications@github.com wrote:

Yeah. But, even with the JWT in the header as

authenticate: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiY3J3X3B1YmxpY19zd2FwcGVyIiwic3dhcHBlcl9pZCI6MjIsImlhdCI6MTUzNTA2NDMxNiwiZXhwIjoxNTM1MTUwNzE2LCJhdWQiOiJwb3N0Z3JhcGhpbGUiLCJpc3MiOiJwb3N0Z3JhcGhpbGUifQ.VTpxqYl_OdooINSwNWyi-BfzammP5cKpFTcOG9_vtiU is returning null.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/graphile/postgraphile/issues/353#issuecomment-415597224, or mute the thread https://github.com/notifications/unsubscribe-auth/AB8M7ehNK5ejD3KQwl_DRbkHKpsMH9hoks5uTzLkgaJpZM4L_KZq.

sjmcdowall commented 6 years ago

Also if you head over to jwt.io with that JWT , what does it decode to?

On Aug 23, 2018, at 6:55 PM, Daniel Marulanda notifications@github.com wrote:

Yeah. But, even with the JWT in the header as

authenticate: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiY3J3X3B1YmxpY19zd2FwcGVyIiwic3dhcHBlcl9pZCI6MjIsImlhdCI6MTUzNTA2NDMxNiwiZXhwIjoxNTM1MTUwNzE2LCJhdWQiOiJwb3N0Z3JhcGhpbGUiLCJpc3MiOiJwb3N0Z3JhcGhpbGUifQ.VTpxqYl_OdooINSwNWyi-BfzammP5cKpFTcOG9_vtiU is returning null.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/graphile/postgraphile/issues/353#issuecomment-415597224, or mute the thread https://github.com/notifications/unsubscribe-auth/AB8M7ehNK5ejD3KQwl_DRbkHKpsMH9hoks5uTzLkgaJpZM4L_KZq.

dfmarulanda commented 6 years ago

Yes, sorry, is Authorization. Isn't working. The JWT have the following information:

{
  "role": "crw_public_swapper",
  "swapper_id": 22,
  "iat": 1535058646,
  "exp": 1535145046,
  "aud": "postgraphile",
  "iss": "postgraphile"
}
sjmcdowall commented 6 years ago

Well hmm... my function I use (and it works perfectly) is

--
-- Utility functions needed throughout the RLS stuff
--
-- Define who we currently are..
--
DROP FUNCTION IF EXISTS mm_public.current_member_id() CASCADE;
create function mm_public.current_member_id() returns int as $$
  select nullif(current_setting('jwt.claims.memberId', true), '')::int;
$$ language sql stable leakproof security definer set search_path from current;
comment on function  mm_public.current_member_id() is
  E'@omit\nHandy method to get the current Member ID for use in RLS policies, etc; in GraphQL, use `currentMember{id}` instead.';

Not sure why yours is not ... although I don't use the jwtPgTypeIdentifier option ...

dfmarulanda commented 6 years ago

Copy/Pasted your function. It did work.