I was wondering if implementing authentication methods beyond Basic Auth (for instance, via GitHub) would be of general interest for the CMS. I would definitely find it useful.
The first step would likely be extracting the authentication logic out of the User class.
As far as I can see, there are two core functional requirements:
- Get the current state: Determine if the user is authenticated via session, cookie, header, etc.
- Perform authentication: Initiate the process, redirect to the login page (internal or external), etc.
Here is a proposed interface to handle this:
export interface AuthProvider {
/**
* Retrieves the current session from the incoming request headers.
* Resolves to `null` if unauthenticated.
*/
getSession(options: { headers: Headers }): Promise<AuthSession | null>;
/**
* Generates the appropriate Response to challenge the user to authenticate.
* For Basic Auth, this would resolve with a 401 and WWW-Authenticate header.
*/
getChallengeResponse(options?: { ... }): Response | Promise<Response>;
}
export interface AuthSession {
user: UserConfiguration;
// session: { ...data... }
}
And an example of its usage in the CMS routing:
.path("/*", async ({ request, next, _ }) => {
const user = new User();
if (this.authProvider && _.join("/") !== "logout") {
const session = await this.authProvider.getSession({
headers: request.headers,
});
if (!session) {
return this.authProvider.getChallengeResponse({
redirectUri: request.url,
});
}
// Simply sets the user config/info the provider has delivered
await user.logIn(session.user);
}
Since I'm not entirely familiar with the project's internals, I'm a bit unsure if this approach aligns with the overall vision. I'd love to get your thoughts on the idea, @oscarotero, whenever you have the time—no rush!
The naming and shape proposed here are loosely based on better-auth. I have also implemented a small PoC to show what this could look like in practice while maintaining backward compatibility (see diff).
Thanks for your time!
I was wondering if implementing authentication methods beyond Basic Auth (for instance, via GitHub) would be of general interest for the CMS. I would definitely find it useful.
The first step would likely be extracting the authentication logic out of the `User` class.
As far as I can see, there are two core functional requirements:
* **Get the current state:** Determine if the user is authenticated via session, cookie, header, etc.
* **Perform authentication:** Initiate the process, redirect to the login page (internal or external), etc.
Here is a proposed interface to handle this:
```ts
export interface AuthProvider {
/**
* Retrieves the current session from the incoming request headers.
* Resolves to `null` if unauthenticated.
*/
getSession(options: { headers: Headers }): Promise<AuthSession | null>;
/**
* Generates the appropriate Response to challenge the user to authenticate.
* For Basic Auth, this would resolve with a 401 and WWW-Authenticate header.
*/
getChallengeResponse(options?: { ... }): Response | Promise<Response>;
}
export interface AuthSession {
user: UserConfiguration;
// session: { ...data... }
}
```
And an example of its usage in the CMS routing:
```ts
.path("/*", async ({ request, next, _ }) => {
const user = new User();
if (this.authProvider && _.join("/") !== "logout") {
const session = await this.authProvider.getSession({
headers: request.headers,
});
if (!session) {
return this.authProvider.getChallengeResponse({
redirectUri: request.url,
});
}
// Simply sets the user config/info the provider has delivered
await user.logIn(session.user);
}
```
Since I'm not entirely familiar with the project's internals, I'm a bit unsure if this approach aligns with the overall vision. I'd love to get your thoughts on the idea, @oscarotero, whenever you have the time—no rush!
The naming and shape proposed here are loosely based on [better-auth](https://better-auth.com/docs/basic-usage#session). I have also implemented a small PoC to show what this could look like in practice while maintaining backward compatibility ([see diff](https://github.com/lumeland/cms/compare/main...esroyo:cms:feat/auth-provider-interface?expand=1)).
Thanks for your time!