Ory & Supabase url shortener: Moving to the Ory Network
Learn how to build a URL shortener using open source ready-to-use solutions.
Ory Guest
Ory's blog has two blog posts about building a URL shortener using Ory Products and Supabase Database. Part 1 covers backend infrastructure and uses Ory Kratos and Oathkeeper. Part 2 covers a frontend part of the application. In this post, I will talk about moving from self-hosted to the Ory Network for the project, and we will discuss a path of migration to the Ory Network.
Why move to the cloud?
When I was building this demo project, I started from the 0.8 version of Ory
Kratos, and once I finished, the 0.9 version was released. I needed to make
minor changes to the configuration, such as changing whitelist_return_urls
to
allowed_return_urls.
That's usually not a big deal. Still, teams must upgrade
their dependencies time-to-time to prevent security issues and have more
features.
The URL shortener project is a demo project and not deployed to any cloud environment, and using the Ory Network can be an overengineering and premature optimization. However, since I decided to deploy the service somewhere, I don't want to deal with the following things on production for Ory Kratos:
- Handle breaking changes for the configuration
- Upgrading version of Ory Kratos
- Running database migrations
- Updating the code not to use deprecated API endpoints
Hence, using the Ory Network seems a good idea because I can have decreased time-to-market and don't worry about upgrading versions of Ory Kratos, especially after the 0.8 release the Ory Network and Ory Kratos have 1:1 compatibility of APIs.
Let's start moving to the cloud, huh?
What services become obsolete after migration? Right now, the app uses the following containers:
kratos
to run Ory Kratos.kratos-migrate
to run migrations against the database.mailslurper
to read sent emails for development purposes.postgres-kratos
to store identity data for Ory Kratos.kratos-selfservice-ui-node
to serve a user interface for login/signup/recovery flows.oathkeeper
that serves as an identity and access proxy for the project..
After the migration to the cloud, we don't need them anymore.
Moving to the Ory Network
As a prerequisite, I needed to create an Ory Network project, and I followed the documentation. In addition, I needed to install an Ory CLI tool. Once I had them installed, I came up with the following migration plan.
- Oathkeeper usage overcomplicates the app. I need to deploy it somewhere near the app, and I have only a couple of rules enabled. I can replace it with a small middleware.
- I don't need Ory Kratos anymore with self-service UI. Hence I need to test everything that would work with the Ory Network.
- I need to use the Ory proxy with the CLI installation for local development.
- Since I don't have any identities created, I can easily migrate without issues and write additional scripts to migrate the data.
Implementing an Ory Network middleware for the backend service. Let's replace
the content of middleware/middleware.go
with the following code
// Copyright © 2023 Ory Corp
// SPDX-License-Identifier: Apache-2.0
package middleware
import (
"net/http"
"github.com/gen1us2k/shorts/config"
"github.com/gin-gonic/gin"
client "github.com/ory/kratos-client-go"
)
type oryCloudMiddleware struct {
client *client.APIClient
conf *config.ShortsConfig
}
func NewMiddleware(c *config.ShortsConfig) *oryCloudMiddleware {
configuration := client.NewConfiguration()
configuration.Servers = []client.ServerConfiguration{
{
URL: c.KratosAPIURL,
},
}
return &oryCloudMiddleware{
client: client.NewAPIClient(configuration),
conf: c,
}
}
func (k *oryCloudMiddleware) Session() gin.HandlerFunc {
return func(c *gin.Context) {
session, err := k.validateSession(c.Request)
if err != nil {
c.Redirect(http.StatusMovedPermanently, k.conf.UIURL)
return
}
c.Set(config.OwnerKey, session.Identity.Id)
c.Next()
}
}
func (k *oryCloudMiddleware) validateSession(r *http.Request) (*client.Session, error) {
// This is simplified version of passing cookies
//
// On the other hand you can use
// r.Cookie.Get("ory_session_projectid") and pass it
// to ToSession function
cookies := r.Header.Get("Cookie")
sess, _, err := k.client.V0alpha2Api.ToSession(r.Context()).
Cookie(cookies).
Execute()
return sess, err
}
One can remove kratos
, oathkeeper
directories and the docker-compose.yml
has the following content:
version: "3.7"
services:
postgres-shorts:
image: postgres:9.6
ports:
- "5432:5432"
environment:
- POSTGRES_USER=shorts
- POSTGRES_PASSWORD=notsecureatall
- POSTGRES_DB=shorts
networks:
- intranet
shorts:
build:
context: .
env_file: .env
ports:
- 8080:8090
networks:
- intranet
networks:
intranet:
Run Ory Proxy
Ory Proxy is a reverse proxy deployed in front of your application. This allows the Ory endpoints to be mirrored on the same domain as the app you're running.
The Proxy rewrites cookies to match the domain your application is currently on.
As a result, the origin of the cookies is set correctly to the domain you run
the app on instead of <your-project-slug>.projects.oryapis.com
.
This behavior is necessary to avoid issues with the browser CORS policy.
We'll use ory proxy
to proxy traffic to the frontend application
ORY_SDK_URL=https://project-slug.projects.oryapis.com ory proxy http://127.0.0.1:3000
Configuring client application
// ...
publicRuntimeConfig: {
kratosUI: process.env.KRATOS_URL || "http://127.0.0.1:4000/.ory/ui",
kratosAPIURL: process.env.KRATOS_API_URL || "http://127.0.0.1:4000/.ory",
apiURL: process.env.API_URL || "http://127.0.0.1:8080",
baseURL: process.env.BASE_URL || "http://127.0.0.1:8080",
},
// Build Configuration: https://go.nuxtjs.dev/config-build
// ...
Running everything together
docker-compose up -d
cd client
npm i
npm run dev
Open http://127.0.0.1:4000
and click Sign In
or Sign Up
buttons
Next steps
- Deploy frontend application to S3
- Deploy backend to AWS lambda
- Add Two Factor Authentication (2FA) to your App
- Add social signin features
- Configure more secure password policies
- Implement email and phone verification and account Activation
Further reading

Back to the future: How today's user behavior around crowd-sourced software is reversing 20 years of security progress

Users are once again blindly running unvetted code. This post explores why security norms are failing in grassroots tech and what must change.

Secure authentication in Next.js: Best practices & implementation
Learn how to add secure auth to Next.js app in minutes, using our step-by-step guide with code examples for server & client components.