On this page

    Tokens

    A token represents a valid session for an authenticated user associated with your application. Each token is designed with the following characteristics:

    • Passwordless: Users only need an active email account to receive a token. There is no requirement for passwords or additional credentials, simplifying the authentication process.
    • Self-contained: Each token embeds everything needed to verify it — the expiration time, a signature and the user’s email — so it can be validated with nothing more than the app configuration and secret.
    • Signed: The token is signed with Ed25519 using a key derived from your App ID and secret, so any modification invalidates the signature.
    • Temporal: Tokens are created with a defined lifespan for security purposes. The expiration time is specified in the application’s configuration during its creation process.

    About the Token Structure

    Tokens are generated by the service and delivered to users via email. They are included as the token query parameter (alongside the user email) in a magic link, which uses the application’s redirect_url. This process ensures that the token reaches the intended recipient and that it is only valid for a limited period.

    A token consists of three parts, separated by a dot:

    <expiration>.<signature>.<email>
    

    For example:

    MjAyNS0wMy0zMVQwMjoyNToyNC4xMjc3NDkrMDI6MDA.6VjTMr+lyUXtxNT7MZ17E/Mvdhtx87bJM8cTQ9El8ERokB+K9ew0AWRkI5vUjmKv1Slq5nvlfdqypege0oXgCg.dXNlckBleGFtcGxlLmNvbQ
    

    Each part is a base64url-encoded value:

    • Expiration: the moment the token expires, encoded from its RFC 3339 timestamp.
    • Signature: the Ed25519 signature over sha256(AppID || email || expiration), computed with a private key deterministically derived from the full secret and the App ID. The signature makes the token tamper-evident: verifying it proves the token was issued by your application and has not been altered.
    • Email: the base64url encoding of the authenticated user’s email address.

    Token secret

    The full secret used to sign tokens is calculated by hashing two parts with sha256: one remains private in the service (to ensure that the token comes from the right instance) and another defined by the app creator (to ensure that it comes from your app).

    Request a Token via the API

    Request a token for a user by sending their email to the POST /tokens endpoint, authenticating with your App ID and secret headers:

    POST /tokens
    X-SIMPLEAUTHLINK-APPID: <your-app-id>
    X-SIMPLEAUTHLINK-SECRET: <your-app-secret>
    Content-Type: application/json
    
    {
      "email": "user@example.com"
    }
    

    A magic link is sent to that email address. The link is the app’s redirect_url with the token and user query parameters appended.

    Verify a Token via the API

    Verify a token (for example, when the user returns through the magic link) by sending it to the PUT /tokens endpoint:

    PUT /tokens
    X-SIMPLEAUTHLINK-APPID: <your-app-id>
    X-SIMPLEAUTHLINK-SECRET: <your-app-secret>
    Content-Type: application/json
    
    {
      "token": "<the-token-from-the-magic-link>"
    }
    

    Response:

    {
      "valid": true,
      "expiration": "2025-03-31T02:25:24.127749+02:00"
    }
    

    Go client examples

    Request and verify a token

    import (
    	"fmt"
    	"log"
    
    	"github.com/simpleauthlink/authapi/api/client"
    	"github.com/simpleauthlink/authapi/token"
    )
    
    func main() {
    	cli, err := client.Default("<your-app-id>", "<your-app-secret>", false)
    	if err != nil {
    		log.Fatal(err)
    	}
    
    	// send a login email to the user
    	err = cli.RequestToken(new(token.Email).SetString("user@example.com"))
    	if err != nil {
    		log.Fatal(err)
    	}
    
    	// the user receives the token by email (the magic link)
    	rawToken := "<the-token-from-the-magic-link>"
    	userToken := new(token.Token).SetString(rawToken)
    
    	// verify it
    	valid, expiresAt, err := cli.VerifyToken(userToken)
    	if err != nil {
    		log.Fatal(err)
    	}
    	if valid {
    		fmt.Printf("session valid until %s\n", expiresAt)
    	}
    }
    

    Verify a token on an incoming request

    Once the user returns through the magic link, the token arrives as a token query parameter on your redirect_url (or as an X-SIMPLEAUTHLINK-TOKEN header). You can validate it inside your HTTP handler:

    // token delivered as a query parameter
    email, valid, err := cli.AuthorizedRequestURLParams(r)
    
    // token delivered as a request header
    email, valid, err := cli.AuthorizedRequestHeaders(r)
    

    Both helpers return the authenticated user’s email and whether the token is currently valid.