# Authentication Design ## Background The initial version of Cherrytwist platform used external Identity Provider (Azure Active Directory) providing authentication following SPA OIDC flows. Cherrytwist Client used [MSAL.js](https://github.com/AzureAD/microsoft-authentication-library-for-js) for client-side authentication and state management. Cherrytwist Server used [PassportJS](http://www.passportjs.org/) and [passport-azure-ad strategy](https://github.com/AzureAD/passport-azure-ad) for validating the JWT tokens and claims issued by AAD and custom GraphQL guard with custom rules for authorizing the requests following Role Based Access Control model (RBAC). Authorization is out-of-scope in the following document and the latest approach is documented in the [Credential Based Authorization](https://hackmd.io/uoAWZwj7RAa0WbZjqEqFTg) document. Complex OIDC / OAuth 2.0 flows that can be used for both authentication and authorization are not used in Cherrytwist. The only claims used explicitly in the application are the email and the token expiry time and no authorization is based on any other account information. There are other mandatory claims specific for each Passport strategy used for validating the issued token (e.g. Client Secret, Issuer etc.). Evolving the Cherrytwist Authentication and Identity Management design and following Open Source Principles a self-service Authentication / Identity provider was seen as indispensable part of the Cherrytwist deployment stack. Evolving the idea, the [Demo Authentication Provider](https://github.com/cherrytwist/demo-authentication-provider) was created to support basic login and user registration flows for demo purposes. The lifespan of the demo authentication provider is coming to an end with the upcoming pre-alpha production release of Cherrytwist and a new provider needs to replace Demo Authentication Provider and provide the following in a safe and secure manner: - user registration - login - user recovery - password changes After evaluation several solutions, the [Ory Identity Platform](https://www.ory.sh/) was chosen as the stack to fill the void of Demo Authentication Provider and provide basic authentication flows. ## Terminology - User Account - an entity providing identity information. In the context of Cherrytwist this is the Identity provided by IdPs. - User Profile - an entity providing the user information in the Cherrytwist domain schema. - Identity Provider (IdP) - a service that creates, maintains, and manages accounts and provides authentication services to relying applications. - Authentication Provider - a service providing authentication. Normally that would be logging in with username:password and being issued cookie / token. - Identity - the "who" of a software system. It can be a customer, employee, user, contractor, or even a programmatic identity such as an IoT device, application, or some other type of "robot." Common aliases are "user", "user account", "account", "subject". In Cherrytwist, we ue User Account. User is used interchangably with User Profile. - Identity Reverse Proxy - a reverse proxy sitting in front of the Upstream Server / Web API that can mutate requests / authorize resource access. ## Phasing # Implementation ## Phase 1 ![](https://i.imgur.com/5FfAE4w.png) In phase 1, the following objectvies are to be met: - Ory Kratos - Login / Register / Logout redirects are handled by CT Client - Ory Kratos is configured to generate ory_kratos_session that is added in CT Client to the Cookie header for GraphQL calls to CT Server - kratos.yml is configured (e.g. cookie and session secrets, endpoints, storage DSN etc.) - Ory Oathkeeper - 2 rules are added - protecting GraphQL POST requests to the upstream CT Server GraphQL API - If Cookie header exists with ory_kratos_session and the cookie_session authenticator doesn't fail, the id_token mutator mutates the request, signs a JWT with an OIDC ID Token that is sent to the CT Server GraphQL API - If the request above fails (e.g. for anonymous GraphQL calls that doesn't have the user authenticated) the handler falls back to noop (no operation) and the request is forwarded to the CT Server GraphQL API 'as-is' - Protecting the Ory Kratos Public API at http(s)://HOST/auth/.ory/kratos/public. If a URL is matched, the .ory/kratos/public URL suffix is stripped and the request is forwarded to the Ory Kratos Public API. - The mutator ID Token JWKS is provided in the config (id_token.jwks.json). - oathkeeper.yml is configured with the correct endpoints (e.g. id_token issuer needs to match the AUTH_ORY_KRATOS_ISSUER env variable so the CT Server can validate the JWT), all relaated config files need to be accessible (e.g. access-rules.json). - Traefik is configured to map the requests to the correct set of services - Ory Kratos & Oathkeeper Helm deployments create the following ### Server CT Server requires a new JWT strategy in order to be able to deserialize the mutated ory_kratos_session. The payload schema can be found in the identity.schema.json. The Ory Strategy can be found at ory.strategy.ts. The rest of the authentication logic is intact and remains standard JWT Strategy & validation. What needs to be provided in order for this to work is the following configuration: - AUTH_ORY_KRATOS_ISSUER / identity.providers.ory_kratos.issuer in Cherrytwist.yml. The token issuer, e.g. https://dev.cherrytwist.org - JWKS_URI / identity.providers.ory_kratos.jwks_uri in Cherrytwist.yml. The JWKS endpoint. It is usually the following http(s)://[Oathkeeper API]/.well-known/jwks.json ### Client The CT Client needs to be able to the the following: - serve Kratos flows / callbacks behind proxy to avoid CORS / CSRF issues - serve login callback - serve logout callback - serve register callback - determine the currently logged in user (whoami) =========================== ## Examples ### Amazon ![](https://i.imgur.com/zRznfHe.png) ### CBAS ![](https://i.imgur.com/MDmqsIK.png)