diff --git a/authentication/methods.mdx b/authentication/methods.mdx index 7eec406..cea60c2 100644 --- a/authentication/methods.mdx +++ b/authentication/methods.mdx @@ -165,6 +165,7 @@ This allows services deployed into the same Kubernetes cluster as Flipt to autom ![Kubernetes Authentication Flow](/images/authentication/kubernetes.svg) When enabled (see our [Configuration: Method Kubernetes](/configuration/authentication#kubernetes) documentation) a service deployed within Kubernetes can read their service account token from local disk and invoke the verify service account operation on the API. + Given the service account is deemed valid for the surrounding cluster this operation will return a valid Flipt client token with a matching expiration as the service account. If your Kubernetes environment has short-lived service account tokens, care will be needed to periodically request a new client token using a newly issued service account token. @@ -261,5 +262,21 @@ func getClientToken(ctx context.Context) (*Response, error) { -The client token found in the body of the response can be used in the authentication bearer header, as outlined in [Using Client Tokens](/authentication/using-tokens). +The client token found in the body of the response can then be used to authenticate with Flipt as outlined in [Using Client Tokens](/authentication/using-tokens). + The expiration can be used to schedule when to next request a new client token. + +## JSON Web Tokens + +[JSON Web Tokens](https://jwt.io/) (JWT) are an open, industry standard RFC 7519 method for representing claims securely between two parties. Flipt supports the use of externally created and signed JWTs as a method of authentication. + +JWT authentication is useful for scenarios where you want to integrate Flipt with an existing authentication system, or where you want to perform service to Flipt authentication without the need to manage static client tokens. + + + JWT authentication is **not** supported by the Flipt UI as it is not a session + compatible authentication method. + + +![JWT Authentication Flow](/images/authentication/jwt.svg) + +The JWT issued by the Authorization Server can then be used to authenticate with Flipt as outlined in [Using JSON Web Tokens](/authentication/using-jwts). diff --git a/authentication/overview.mdx b/authentication/overview.mdx index e548203..3240844 100644 --- a/authentication/overview.mdx +++ b/authentication/overview.mdx @@ -50,6 +50,14 @@ Flipt supports multiple authentication methods for acquiring credentials: Once a `client token` has been acquired, it can be supplied via request metadata dependent on the protocol. Both HTTP and gRPC examples can be found on the [Using Client Tokens](/authentication/using-tokens) page. +## JSON Web Tokens + +Flipt can also authenticate requests using externally created and signed [JSON Web Tokens](https://jwt.io/). This is useful for integrating existing authentication systems with Flipt. + +To enable JWT authentication, you will need to configure Flipt with the public key used to verify the JWT signature. + +See the [Configuration: JWT Authentication](/configuration/authentication#json-web-token) documentation for details. + ## Authorization Currently, Flipt only supports authentication without any extended authorization capabilities. diff --git a/authentication/using-jwts.mdx b/authentication/using-jwts.mdx new file mode 100644 index 0000000..1fec9ea --- /dev/null +++ b/authentication/using-jwts.mdx @@ -0,0 +1,88 @@ +--- +title: Using JSON Web Tokens +description: This document explains how to handle JSON Web Tokens via both HTTP and gRPC. +--- + +## HTTP + +JSON Web Tokens can only be presented via HTTP requests in the form of an `Authorization` header. + +### `Authorization` Header + +For applications that communicate with Flipt over HTTP, the `Authorization` header is required. + +It must be provided in the form `Authorization: JWT `. + +The following examples illustrate this in the context of various programming languages: + + + +{/* prettier-ignore */} +```go client.go +import ( + "context" + "net/http" +) + +func main() { + req := http.NewRequest("GET", "https://flipt.your.instance/api/v1/flags", nil) + req.Header.Set("Authorization", "JWT eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c") + + resp, err := http.Do(req) + // ... +} +``` + +{/* prettier-ignore */} +```typescript client.ts +import fetch from 'node-fetch'; + +const headers = { 'Authorization': 'JWT eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c' } +const response = await fetch('https://flipt.your.instance/api/v1/flags', { headers: headers }) +``` + +{/* prettier-ignore */} +```python client.py +import requests + +def doRequest(): + + headers ={"Authorization": "JWT eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"} + requests.get("https://flipt.your.instance/api/v1/flags", headers=headers) + + return +``` + + + +## GRPC + +For gRPC we use the [Metadata](https://grpc.io/docs/what-is-grpc/core-concepts/#metadata) functionality similar to HTTP Headers. +The lower-case `authorization` metadata key should be supplied with a single string `JWT ` to any RPC calls. + +### Example + +The following example authenticates a single gRPC client request: + +```go rpc.go +func DoRequest(ctx context.Context, flagKey string) { + ctx := metadata.AppendToOutgoingContext(ctx, "authorization", "JWT eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c") + + flag, err := flipt.GetFlags(ctx, &flipt.GetFlagRequest{ + Key: flagKey, + }) + + //... +} +``` + +This subsequent example demonstrates using a client unary interceptor, which authenticates all outgoing requests: + +```go interceptor.go +func AuthUnaryClientInterceptor(optFuncs ...CallOption) grpc.UnaryClientInterceptor { + return func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error { + ctx = metadata.AppendToOutgoingContext(ctx, "authorization", "JWT eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c") + return invoker(ctx, method, req, reply, cc, opts...) + } +} +``` diff --git a/configuration/authentication.mdx b/configuration/authentication.mdx index ce61445..b599829 100644 --- a/configuration/authentication.mdx +++ b/configuration/authentication.mdx @@ -218,7 +218,7 @@ To enable this, you must set the [`use_pkce`](/configuration/overview#authentica #### Example: OIDC With Google - Checkout our new [Login with Google](/guides/login-with-google) guide for an + Checkout our [Login with Google](/guides/login-with-google) guide for an in-depth look into configuring Google as an OIDC provider. @@ -334,10 +334,82 @@ authentication: service_account_token_path: /var/run/secrets/kubernetes.io/serviceaccount/token ``` -Once enabled, client tokens can be retrieved by sending a Kubernetes pod's service account token to the [VerifyServiceAccount](/reference/authentication/kubernetes-verify-service-account) operation in the API. +Once enabled, client tokens can be retrieved by sending a Kubernetes pod's service account token to the `VerifyServiceAccount` operation in the API. Further explanation for using this method can be found in the [Authentication: Kubernetes](/authentication/methods#kubernetes) documentation. +### JSON Web Token + +The `jwt` method provides the ability to authenticate with Flipt using an externally issued JSON Web Token. This method is useful for integrating with other authentication systems that can issue JWTs (e.g. [Auth0](https://auth0.com/docs/tokens/json-web-tokens)) or by generating your own signed JWTs on the fly. + +Flipt supports asymmetrically signed JWTs using the following algorithms: + +- RS256 +- RS512 +- ES256 +- ES512 +- EdDSA + +This means that the JWT must be signed using a private key leveraging one of these algorithms and Flipt must be configured with the corresponding public key. + +Flipt supports key verification using the following methods: + +- [JWKS](https://auth0.com/docs/secure/tokens/json-web-tokens/json-web-key-sets) URL (JSON Web Key Set URL) +- PEM (Privacy Enhanced Mail) encoded public key + + + These methods are mutually exclusive, meaning that only one of them can be + configured at a time. + + +#### JWKS URL + +The `jwks_url` configuration value is a URL that points to a JWKS (JSON Web Key Set) endpoint. This endpoint must return a JSON object that contains a list of public keys that can be used to verify the JWT signature. + +```yaml config.yaml +authentication: + methods: + jwt: + enabled: true + jwks_url: https://auth0.com/.well-known/jwks.json +``` + +#### PEM Encoded Public Key + +The `public_key_file` configuration value is the path to a PEM encoded public key that can be used to verify the JWT signature. + +```yaml config.yaml +authentication: + methods: + jwt: + enabled: true + public_key_file: /path/to/public_key.pem +``` + +#### Claim Validation + +Flipt supports validating the following claims: + +- `iss` (issuer) +- `aud` (audience) +- `exp` (expiration time) +- `nbf` (not before) +- `iat` (issued at) + +The `exp`, `nbf`, and `iat` claims are validated by default. + +To enable claim validation, configure the values in the `validate_claims` configuration option to the expected values. + +```yaml config.yaml +authentication: + methods: + jwt: + enabled: true + validate_claims: + issuer: https://auth0.com/ + audiences: https://flipt.io/, https://flipt.com/ # at least one audience must match +``` + ### Common Properties: Cleanup Each authentication method contains a nested `cleanup` configuration object. diff --git a/configuration/overview.mdx b/configuration/overview.mdx index 311acfc..a9ce68a 100644 --- a/configuration/overview.mdx +++ b/configuration/overview.mdx @@ -187,6 +187,16 @@ export FLIPT_CORS_ALLOWED_ORIGINS="http://localhost:3000 http://localhost:3001" | authentication.methods.kubernetes.ca_path | Kubernetes API CA certification path | /var/run/secrets/kubernetes.io/serviceaccount/ca.crt | v1.19.0 | | authentication.methods.kubernetes.service_account_token_path | Path to Flipt service account token | /var/run/secrets/kubernetes.io/serviceaccount/token | v1.19.0 | +#### Authentication Methods: JWT + +| Property | Description | Default | Since | +| ---------------------------------------------------- | --------------------------------------------------- | ------- | ------- | +| authentication.methods.jwt.enabled | Enable JWT authentication | false | v1.35.0 | +| authentication.methods.jwt.jwks_url | URL to retrieve JWKS for JWT validation | | v1.35.0 | +| authentication.methods.jwt.public_key_file | Path to public key file for JWT validation | | v1.35.0 | +| authentication.methods.jwt.validate_claims.issuer | The issuer claim to validate on JWT tokens | | v1.35.0 | +| authentication.methods.jwt.validate_claims.audiences | The audience claim (list) to validate on JWT tokens | | v1.35.0 | + ### Database | Property | Description | Default | Since | diff --git a/images/authentication/jwt.svg b/images/authentication/jwt.svg new file mode 100644 index 0000000..d59d86e --- /dev/null +++ b/images/authentication/jwt.svg @@ -0,0 +1,108 @@ +JWT Authentication FlowAuthorization ServerApplication ClientFlipt Server issues a signed (Private Key) JWTAPI Request with JWT (Authorization)Verifies JWT claims and signature (Public Key) + + + + + + + + + \ No newline at end of file diff --git a/mint.json b/mint.json index ee8545b..5e49ae4 100644 --- a/mint.json +++ b/mint.json @@ -168,7 +168,8 @@ "pages": [ "authentication/overview", "authentication/methods", - "authentication/using-tokens" + "authentication/using-tokens", + "authentication/using-jwts" ] }, {