coupergateway / couper

Couper is a lightweight API gateway designed to support developers in building and operating API-driven Web projects
https://couper.io
MIT License
85 stars 15 forks source link

Reference token AC #711

Open johakoch opened 1 year ago

johakoch commented 1 year ago

E.g. for the "Use-once" tokens use-case, I'm thinking about a (non-JWT) reference token AC. These tokens could be created (token endpoint) and stored (e.g. for a defined time) in a database by a (non-Couper) service, introspected (introspection endpoint) and revocated (revocation endpoint) by a client (Couper).

Couper acting as an OAuth2 resource server provides an access control using token introspection from https://github.com/avenga/couper/issues/632.

The configuration could be quite similar to the jwt block configuration, but without the JWT-specific attributes:

beta_reference_token "rt" {
  cookie = "..."
  # OR
  header = "..."
  # OR
  token_value = ...
  # OR ...

  disable_private_caching = ...

  claims = {...}
  required_claims = [...]

  permissions_claim = "..."
  permissions_map = {...}
  # OR
  permissions_map_file = "..."

  roles_claim = "..."
  roles_map = {...}
  # OR
  roles_map_file = "..."

  beta_introspection { # mandatory
    # ...
  }
}

Quite some code could probably be reused/refactored from the JWT access control implementation.

However, there is at least one issue: The error cases in the new access control would be very similar to the ones in the JWT access control (missing/invalid/expired). But currently the errors are called errors.Jwt... with their counterpart jwt and jwt_token_... error types. We cannot just rename existing error types (because they are part of the contract). And I'm not sure whether it is possible to derive more generic token and token_ error types from the JWT specific ones (cf. error "hierarchy").

johakoch commented 1 year ago

Works:

$ git diff
diff --git a/errors/type_defintions.go b/errors/type_defintions.go
index 22685421..d5992a1e 100644
--- a/errors/type_defintions.go
+++ b/errors/type_defintions.go
@@ -11,9 +11,13 @@ var Definitions = []*Error{
        AccessControl.Kind("basic_auth").Kind("basic_auth_credentials_missing").Status(http.StatusUnauthorized),

        AccessControl.Kind("jwt"),
-       AccessControl.Kind("jwt").Kind("jwt_token_expired"),
-       AccessControl.Kind("jwt").Kind("jwt_token_invalid"),
-       AccessControl.Kind("jwt").Kind("jwt_token_missing").Status(http.StatusUnauthorized),
+       AccessControl.Kind("jwt").Kind("token"),
+       AccessControl.Kind("jwt").Kind("token").Kind("jwt_token_expired"),
+       AccessControl.Kind("jwt").Kind("token").Kind("jwt_token_expired").Kind("token_expired"),
+       AccessControl.Kind("jwt").Kind("token").Kind("jwt_token_invalid"),
+       AccessControl.Kind("jwt").Kind("token").Kind("jwt_token_invalid").Kind("token_invalid"),
+       AccessControl.Kind("jwt").Kind("token").Kind("jwt_token_missing").Status(http.StatusUnauthorized),
+       AccessControl.Kind("jwt").Kind("token").Kind("jwt_token_missing").Kind("token_missing").Status(http.StatusUnauthorized),

        AccessControl.Kind("oauth2"),

Throwing error.Token instead of errors.JWT and errors.Token... instead of errors.JwtToken..., the errors can then be handled by error_handlers for either jwt or token, token_... or jwt_token_... error types.

That way we could throw the new (token) errors, introduce new (token) error types, and deprecate the old (jwt) error types, allowing both during a transition phase.

johakoch commented 1 year ago

Reference tokens are offered by e.g.