Quickstart
This quickstart guide will walk through some magiclinksdev examples on your local machine.
This guide uses the default quickstart configuration. This includes a no-operation email sender and robots will not be prevented from following magic links. For details on how to doa more advanced self-hosted configuration, please visit the Configuration docs.
Prerequisites
This example requires Go, Git, and Docker to be installed on your machine.
The following Docker images will be pulled by Docker Compose automatically.
micahparks/magiclinksdevnop:latest
postgres:17
Step 1: Clone the repository
Download the open-source project using Git.
git clone https://github.com/MicahParks/magiclinksdev.git
cd magiclinksdev
Step 2: Use Docker Compose
Launch the service and its database in the background using Docker Compose.
docker compose up -d
Step 3: Create a magic link
The example from the repository in examples/client/magic_link_create/
will request a magic link from the service. This
will perform a magic link create request.
go run examples/client/magic_link_create/main.go
The output should look similar to this:
{
"linkCreateResults": {
"magicLink": "http://localhost:8080/redirect/?secret=66af8a5d-7e8d-4f9f-9729-161e214c7d1c",
"secret": "66af8a5d-7e8d-4f9f-9729-161e214c7d1c"
},
"requestMetadata": {
"uuid": "b56640e4-242d-4bbf-a7b5-1c678502eb5d"
}
}
Step 4: Use the magic link
Copy the magic link and open it in a browser. You should be redirected to jwtdebug.micahparks.com with a signed JWT in a URL query parameter. Each magic link can only be visited once.
This website is a slimmed down version of the jsonwebtoken.github.io GitHub project.
Header:
{
"alg": "EdDSA",
"kid": "526ff60f-9c8b-4a73-ba74-cc8962494873",
"typ": "JWT"
}
Payload:
{
"foo": "bar",
"iss": "http://localhost:8080",
"aud": [
"ad9e9d84-92ea-4f07-bac9-5d898d59c83b"
],
"exp": 1673815954,
"nbf": 1673815654,
"iat": 1673815654,
"jti": "1a1e2abe-b467-4bf6-9194-c4a60c54745b"
}
Every API client needs to validate the aud
claim in the JWT. This is essential to prevent a malicious service
account from requesting a signed JWT for a different service. Every service account has at least one aud
given on creation. The iss
claims should be checked too. The iss
claim is specific to the configuration of the
magiclinksdev service, typically the URL.
Step 5: Create a One-Time Password (OTP)
The example from the repository in examples/client/otp_create/
will request an OTP from the service. The response will
contain the requested OTP and its public ID. This will preform an
OTP create request.
go run examples/client/otp_create/main.go
The output should look similar to this:
{
"otpCreateResults": {
"id": "bd0dcb53-9fbc-46f6-bba4-13f4fd6478b6",
"otp": "470594"
},
"requestMetadata": {
"uuid": "d08fcdd1-6ad8-43f4-ba40-dfd12e9bf639"
}
}
Step 6: Validate the OTP
The example from the repository in examples/client/otp_validate/
will validate a given OTP. Both the OTP and its
public ID are required for validation. Each OTP can only be successfully validated once. This will preform a
OTP validate request.
Replace the -id
and -otp
flags with the values from the previous step.
go run examples/client/otp_validate/main.go -id bd0dcb53-9fbc-46f6-bba4-13f4fd6478b6 -otp 470594
The output should look similar to this:
{
"otpValidateResults": {},
"requestMetadata": {
"uuid": "5d888a89-e5f6-4e79-8251-987c1d9793c2"
}
}
Step 7: Create a JWT manually
Unlike magic links, a JWT is not issued after OTP validation. Instead, create a JWT manually after a user's OTP is validated.
The example from the repository in examples/client/jwt_create/
will create a JWT. The response will contain the signed
JWT with the requested claims. This will preform a JWT create request.
go run examples/client/jwt_create/main.go
The output should look similar to this:
{
"jwtCreateResults": {
"jwt": "eyJhbGciOiJFZERTQSIsImtpZCI6ImE3YWNmNzRmLTcxZjYtNGU0MC05OTQ4LTZjY2E0MjYyZGJmZCIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODAiLCJhdWQiOlsiYWQ5ZTlkODQtOTJlYS00ZjA3LWJhYzktNWQ4OThkNTljODNiIl0sImV4cCI6MTcyOTk1OTQ3NywibmJmIjoxNzI5OTU5MTc3LCJpYXQiOjE3Mjk5NTkxNzcsImp0aSI6IjM4Y2M4ZDQ5LTM3MTYtNDk0MC1hYTBjLWU0YzZiYzk4Mzg2YiJ9.j45VHJ4s0jV-Nae79VK3M_xMu6SIK_RNPJPhqPWMqU-ZI2hSigf3JQ-g0M5cQASZ6uDPOiCGSgs-fMt-NNk9BQ"
},
"requestMetadata": {
"uuid": "5b9afacb-0801-4048-8479-eeec04b4254c"
}
}
Step 8: Cleanup
Stop the service and the database running in the background.
docker compose down
Disclaimer
Please note that the quickstart configuration should not be used in production. It is essential to regenerate all UUIDs, especially the admin API key. Additionally, a new storage AES-256-GCM key should be generated.
Any UUIDs and storage AES-256-GCM keys should be generated with sufficient entropy. On Linux systems the following commands can accomplish this:
Generate a random UUID on Linux
uuidgen --random
Generate a AES-256-GCM key on Linux
openssl rand -base64 32
Conclusion
You have successfully self-hosted magiclinksdev on your local machine! You can now configure the service for your use case and request magic links for your own applications. See the Configuration reference for more information.
Want to say thanks for writing up the docs? Support the project financially? Consider becoming a GitHub Sponsor.