PostgREST / postgrest

REST API for any Postgres database
https://postgrest.org
MIT License
23.3k stars 1.02k forks source link

Suggestion: token introspection endpoint #1402

Open raphet opened 4 years ago

raphet commented 4 years ago

Story

As an application owner storing authentication & authorization information in a central postgre database - accessible via postgREST API - I am deploying multiple distributed/independent resource servers/services. Those need to be able to verify authentication & authorization of accessing consumers/users a) without storing the sensitive central JWT secret & b) without employing a separate authentication/authorization db/table.

Suggestion

A token introspection point allows this. A resource server can call such an introspection point to verify the authentication/authorization of a user-presented jwt token. The resource server itself would not be able to view the full authorization scope, only wether this particular token allowed this particular user to access this particular resource server/service.

In @steve-chavez 's words:

The rough idea is to create a stored procedure and expose it through /rpc/token_introspection only to authenticated users — anonymous users don't have GRANT EXECUTE on that sp(make sure to read the warning in function privileges). In that sp you could have logic to get the jwt claims you need and output the "example response" mentioned in the article. I think there'd be no risk of an authenticated user checking other users jwt's since he can only send it's own valid jwt to the sp.

Further discussion

General caution is required in handling jwt tokens & refresh tokens, good practice inputs (e.g. about using asymmetric JWT signatures) can be found on a pingidentity post about jwt-security.

dwagin commented 4 years ago

https://gitlab.com/dwagin/pg_ed25519 https://gitlab.com/dwagin/pgjwt_ed25519 asymmetric JWT signatures

steve-chavez commented 4 years ago

@raphet Did you manage to solve the issue? @dwagin suggestion helped?

raphet commented 4 years ago

@steve-chavez no, I thought, dwagin's comment was meant as closure. I did not solve the issue, so far.

steve-chavez commented 4 years ago

I've been checking RFC 7662 and it seems that the introspection endpoint cannot be done with the idea I presented before(a proc in the db).

This is because PostgREST would reject an expired token before it reaches the db, and the active field would not be computed.

@raphet I'm reopening for further investigation(have to do some reading). I think we should support this use case.

@dwagin suggestion helps in the case where you'd share the public key with the resource servers. (also really useful since we only document using symmetric keys with pg for now).

steve-chavez commented 4 years ago

I see two options for doing this:

  1. In Haskell: Offering a /token_introspection endpoint that would output the desired response by using our JWT lib. This endpoint would be disabled by default and enabled with a config option. We would also have to offer an Nginx conf for filtering this endpoint to the public.

  2. In SQL: We'd have to offer a way to disable PostgREST JWT validation and let the user do the JWT validation and ROLE switching himself in the pre-request func(@witsch has requested this before). Then you'd have all the control over the JWT and you could make a custom token_introspection proc that can compute the active field.

1 would be easier to implement but I think 2 would be more adequate because this is an advanced use case.

If 2 were to be implemented we'd have to keep enforcing safety somehow. Maybe still switch to the db-anon-role by default(user could override it) and detect that the pgjwt extension is present. We'd also have to offer a default SQL lib that gets the jwt claims as GUCs(request.jwt.claim.*) so our RLS samples would still be valid.