Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
d7c4327
chore: integrate builder in dev server for simplified maintenance
schettn Feb 5, 2025
eee120e
perf(pylon-dev): implement esbuild watch mode and notify plugin for i…
schettn Feb 6, 2025
b7f8b4b
fix(dependencies): replace treekill with ps-tree for process management
schettn Feb 6, 2025
dfb5c77
feat(pylon): extend plugin system with middleware and app setup support
schettn Feb 6, 2025
65bc196
feat(pylon): add support for plugin build lifecycle
schettn Feb 6, 2025
0b965bf
feat(pylon): add landing page support and unhandled route plugin
schettn Feb 6, 2025
f228add
feat(auth): overhaul authentication system with new useAuth plugin an…
schettn Feb 6, 2025
6fd91c7
feat(pylon): add pages plugin and use pm2 for dev server
schettn Feb 11, 2025
4854f46
Merge branch 'main' into pylon-dev-rework
schettn Feb 11, 2025
90e0863
add chokidar as a dev dependency
schettn Feb 11, 2025
b2b63f4
update chokidar import to use FSWatcher type
schettn Feb 11, 2025
6f25217
chore: update pylon and pylon-dev dependencies to canary version
schettn Feb 11, 2025
3d13feb
update @gqty/cli to 4.2.5 and add pm2, esbuild, and esbuild-plugin-ts…
schettn Feb 11, 2025
8acee79
add chokidar and postcss-load-config as dependencies in package.json
schettn Feb 11, 2025
347fb15
update pages.json file with page routes if changed
schettn Feb 11, 2025
f2dce96
add @tailwindcss/postcss as a devDependency in package.json
schettn Feb 11, 2025
725602a
use getEnv() to retrieve environment variables in disableCacheMiddleware
schettn Feb 12, 2025
d18431f
optimize file handling in bundler and use Promise.all for concurrent …
schettn Feb 12, 2025
fb43064
add @gqty/react and gqty as dependencies in package.json
schettn Feb 12, 2025
a67cee6
update pnpm-lock.yaml to include @gqty/react, gqty, and @tailwindcss/…
schettn Feb 12, 2025
4549283
add @gqty/react and gqty as dependencies, and @tailwindcss/postcss as…
schettn Feb 12, 2025
0b12573
enable minification in build process for improved performance
schettn Feb 12, 2025
e920a49
fix: update imports and module resolution for improved organization a…
schettn Feb 18, 2025
add4312
update pages template
schettn Feb 18, 2025
9828f8d
add tsconfig.pylon.json path to package.json
schettn Feb 18, 2025
dc6307c
add public directory copying and serve static files in setup
schettn Feb 18, 2025
aaa5846
trim log output to remove unnecessary whitespace
schettn Feb 18, 2025
5fd3a97
remove unnecessary console.log statements for cleaner output
schettn Feb 18, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/breezy-socks-deliver.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@getcronit/pylon-dev': patch
---

Integrate builder in dev server.
This simplifies the maintaince and future development.
13 changes: 13 additions & 0 deletions .changeset/curly-tools-itch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
'@getcronit/pylon': minor
---

Show a fallback page for the landing page and unhandled routes / 404s.

This behavior can be disabled via the pylon config:

```ts
export const config: PylonConfig = {
landingPage: false
}
```
24 changes: 24 additions & 0 deletions .changeset/ninety-toys-shout.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
'@getcronit/pylon-dev': minor
'@getcronit/pylon': minor
---

Add new plugin build hook to allow custom esbuild builds.
The build hook is currently called before the pylon main build process.
It does not re-run during watch mode, so you need to implement your own watch logic.

Example:

```ts
function usePagesPlugin(): Plugin {
return {
build: async () => {
// Custom esbuild build
}
}
}

export const config: PylonConfig = {
plugins: [usePagesPlugin()]
}
```
7 changes: 7 additions & 0 deletions .changeset/proud-trees-end.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'create-pylon': minor
'@getcronit/pylon-dev': minor
'@getcronit/pylon': minor
---

Add pages plugin and use pm2 for dev server
5 changes: 5 additions & 0 deletions .changeset/real-fans-jog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@getcronit/pylon-dev': patch
---

Use esbuild watch mode instead of re-building from scratch.
5 changes: 5 additions & 0 deletions .changeset/six-vans-care.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@getcronit/pylon-dev': patch
---

replace `treekill` with `ps-tree`
36 changes: 36 additions & 0 deletions .changeset/stale-lobsters-flash.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
'@getcronit/pylon': major
---

**Summary:**
This changeset introduces a major overhaul to the built-in authentication system. The new implementation automatically sets up `/auth/login`, `/auth/callback`, and `/auth/logout` routes, injects an `auth` object into the context, and manages token cookies. Role-based route protection is now enhanced via `authMiddleware` and the updated `requireAuth` decorator, configurable through the streamlined `useAuth` plugin.

---

**Breaking Changes:**

- **WHAT:**
The authentication configuration has been completely revamped. The previous manual setup is replaced by the `useAuth` plugin. Custom authentication route definitions are no longer necessary, and existing middleware or decorator usage may require adjustments.

- **WHY:**
This change was implemented to simplify authentication setup, reduce boilerplate, improve security by automating context and cookie management, and offer better role-based access control.

- **HOW:**
Consumers should:
1. Remove any custom authentication route setups.
2. Update their configuration to use the new `useAuth` plugin as shown below:
```typescript
export const config: PylonConfig = {
plugins: [
useAuth({
issuer: 'https://test-0o6zvq.zitadel.cloud',
endpoint: '/auth',
keyPath: 'key.json'
})
]
}
```
3. Replace previous authentication middleware or decorators with the updated `requireAuth` and `authMiddleware` APIs.
4. Test the new authentication endpoints (`/auth/login`, `/auth/callback`, and `/auth/logout`) to ensure proper integration.

Ensure you update your code accordingly to avoid disruptions in your authentication flow.
32 changes: 32 additions & 0 deletions .changeset/tall-spies-joke.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
'@getcronit/pylon': minor
---

Extend plugin system with middleware and app setup support.
The viewer is now integrated via a built-in `useViewer` plugin.

Custom plugins can now acces the app instance and register middleware and setup functions.:

```ts
import {Plugin} from '@getcronit/pylon'

export function myPlugin(): Plugin {
return {
setup(app) {
app.use((req, res, next) => {
console.log('Request:', req.url)
next()
})

app.get('/hello', (req, res) => {
res.send('Hello, World!')
})
},
middleware: (c, next) => {
// This middleware will be inserted higher in the middleware stack
console.log('Middleware:', c.req.url)
next()
}
}
}
```
Original file line number Diff line number Diff line change
Expand Up @@ -2,65 +2,86 @@ import {Callout} from '@components/callout'

# Built-in Authentication and Authorization

Discover how Pylon simplifies user authentication and authorization with its comprehensive built-in features, empowering you to secure your web services effortlessly.
Pylon now offers an enhanced, streamlined authentication system. With this update, the auth endpoint automatically creates routes for **/auth/login**, **/auth/callback**, and **/auth/logout**. When a user authenticates, Pylon sets an `auth` object in the context variables and automatically manages a cookie with the token—simplifying session management and ensuring a secure experience.

---

## General Setup

Before diving into authentication and authorization with Pylon, it's essential to set up your environment and configure the necessary components. Pylon's built-in authentication system follows the OIDC standard and is currently tightly integrated with ZITADEL for user management and access control.
Before you begin, configure your environment to integrate with your authentication provider (e.g., ZITADEL). The new configuration uses the `useAuth` plugin to initialize authentication routes and settings.

1. **Environment Variables:**
Ensure you have the required environment variables set up in your project:
```typescript
import {
app,
PylonConfig,
requireAuth,
useAuth,
authMiddleware
} from '@getcronit/pylon'

export const config: PylonConfig = {
plugins: [
useAuth({
issuer: 'https://test-0o6zvq.zitadel.cloud',
endpoint: '/auth', // optional, default is '/auth'
keyPath: 'key.json' // optional, default is 'key.json'
})
]
}
```

```
AUTH_ISSUER=https://test-0o6zvq.zitadel.cloud
AUTH_PROJECT_ID=<your_auth_project_id>
```
**How it works:**

2. **Integration with ZITADEL:**
To enable Pylon to authenticate users and manage access control, you need to integrate it with ZITADEL. Follow the documentation provided by ZITADEL to set up projects, applications, keys, and roles.
[ZITADEL Projects Documentation](https://zitadel.com/docs/guides/manage/console/projects)
- **Auth Routes:**
The plugin automatically creates routes for:

- `/auth/login`
- `/auth/callback`
- `/auth/logout`

- **Context & Cookie:**
After authentication, an `auth` object is added to your context, and a cookie containing the token is set for subsequent requests.

<Callout type="note" title="Important">
Pylon requires a **API** application with the **Private JWT Key** type to
authenticate users and manage access control.
Ensure that your API application is configured to use a **Private JWT Key**
type for secure token management.
</Callout>

---

## Authentication Example

Pylon makes authentication seamless by providing a straightforward integration with ZITADEL. Here's how you can set up authentication in your Pylon project:
To protect sensitive data, use the `requireAuth` decorator. In the example below, any user trying to access the data must be authenticated:

```typescript
import {app, auth, requireAuth} from '@getcronit/pylon'

// Define your sensitive data service
// Define a service for sensitive data
class SensitiveData {
@requireAuth()
static async getData() {
return 'Sensitive Data'
}
}

// Expose the resolver via GraphQL
export const graphql = {
Query: {
sensitiveData: SensitiveData.getData
}
}

app.use('*', auth.initialize())

export default app
```

In this example, the `requireAuth()` decorator ensures that users are authenticated before accessing sensitive data. You can also specify roles to restrict access to certain data based on user permissions.
In this setup, the `@requireAuth()` decorator ensures that only authenticated users can access the `getData` method. If the user is not authenticated, they will be redirected to the login flow at `/auth/login`.

---

## Authorization Example

Authorization in Pylon allows you to control access to specific resources based on user roles and permissions. Here's how you can implement authorization in your Pylon project:
If you need to restrict access based on roles, you can pass a roles array to the `requireAuth` decorator. For instance, the following example limits access to users with the `"admin"` role:

```typescript
// Define your sensitive data service
// Define a service for admin-only data
class SensitiveData {
@requireAuth({
roles: ['admin']
Expand All @@ -70,72 +91,63 @@ class SensitiveData {
}
}

// Define your GraphQL schema
// Expose the resolver via GraphQL
export const graphql = {
Query: {
sensitiveAdminData: SensitiveData.getAdminData
}
}

app.use('*', auth.initialize())

export default app
```

In this example, the `requireAuth()` decorator ensures that only authenticated users with the "admin" role can access the `getAdminData()` function. You can customize roles and permissions according to your application's requirements.
Only authenticated users who have the `"admin"` role will be allowed to access `getAdminData()`. Roles should be managed in your authentication provider (e.g., ZITADEL) for centralized control over permissions.

Roles can be defined in ZITADEL and assigned to users to control access to specific resources. By integrating Pylon with ZITADEL, you can easily manage roles and permissions for your application.
For more information on setting up roles in ZITADEL, refer to the [ZITADEL Roles Documentation](https://zitadel.com/docs/guides/manage/console/roles).
---

## Securing Routes
## Securing Routes with Middleware

Securing routes in Pylon involves enforcing authentication and, optionally, authorization for specific endpoints or routes. Here's how you can secure a route in your Pylon project:
In addition to securing individual resolvers, you can enforce authentication and authorization for entire routes using the new `authMiddleware`. For example, to secure a specific REST endpoint:

```typescript
import {auth, requireAuth} from '@getcronit/pylon'

// Define your sensitive data service
class SensitiveData {
static async getData() {
return 'Sensitive Data'
}
import {authMiddleware} from '@getcronit/pylon'

@requireAuth({
// Secure all routes under /admin to only allow users with the 'admin' role
app.use(
'/admin',
authMiddleware({
roles: ['admin']
})
static async getAdminData() {
return 'Admin Data'
}
}
)

export const graphql = {
Query: {
sensitiveData: SensitiveData.getData,
sensitiveAdminData: SensitiveData.getAdminData
// Secure specific route to only allow users with the 'admin' role
app.get(
'/secure',
authMiddleware({
roles: ['admin']
}),
c => {
return c.json({data: 'sensitive'})
}
}

// Enforce authentication for all routes
app.use('*', auth.initialize())

// Secure a specific route with authentication and authorization
app.use('/admin', auth.requireAuth({roles: ['admin']}))

)
export default app
```

In this example, we're securing the `/admin` route to ensure that only authenticated users with the "admin" role can access it. By using the `requireAuth()` middleware from Pylon's authentication module, we enforce both authentication and authorization for this specific route.
In this case, any request to the `/admin` route will first pass through `authMiddleware`, ensuring that the user is authenticated and has the required `"admin"` role.
The same applies to the `/secure` route, which is secured with the `authMiddleware` middleware.

You can customize the route and the required roles according to your application's requirements. This ensures that sensitive endpoints are protected, providing a secure environment for your users' data and resources.
---

## Further Resources

For detailed instructions on setting up projects, applications, keys, and roles in ZITADEL, refer to the ZITADEL documentation:
For additional guidance on integrating with your authentication provider, please refer to the following resources:

- [ZITADEL Projects Documentation](https://zitadel.com/docs/guides/manage/console/projects)
- [ZITADEL Applications Documentation](https://zitadel.com/docs/guides/manage/console/applications#api)
- [ZITADEL Roles Documentation](https://zitadel.com/docs/guides/manage/console/roles)

---

## Conclusion

With Pylon's built-in authentication and authorization features, you can easily secure your web services and control access to sensitive data, providing a seamless and secure user experience.
With the new built-in authentication and authorization features, Pylon makes securing your web services simpler than ever. The automatic route creation, context management, and cookie handling streamline the login flow, while decorators and middleware give you granular control over access to your application’s data and routes. Enjoy a secure and seamless user experience with minimal configuration!
15 changes: 15 additions & 0 deletions examples/pages/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
node_modules
Dockerfile*
docker-compose*
.dockerignore
.git
.gitignore
README.md
LICENSE
.vscode
Makefile
helm-charts
.env
.editorconfig
.idea
coverage*
Loading
Loading