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

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"
  }
}

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"
}

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.