Link Types
DyLy supports four distinct types of links, each designed for specific use cases. Understanding these link types will help you choose the right solution for your needs.
Overview
- URL Link: Redirects users to a registered URL - perfect for link shortening and tracking
- JSON Link: Returns registered JSON data - ideal for static endpoints and configuration
- JWT Link: Returns a cryptographically signed JWT with your JSON payload - secure data delivery
- Deep Link: Launches mobile apps from web links - seamless app integration
URL Link
URL links are the most straightforward type - they redirect visitors to a specified destination URL. This is the classic "link shortener" functionality.
How It Works
- User clicks the short link (e.g.,
https://myapp.dyly.dev/promo) - DyLy server receives the request and validates the link
- Server responds with an HTTP 302 redirect to the destination URL
- User's browser automatically follows the redirect to the final destination
Key Features
- Simple Redirection: One-to-one mapping from short URL to destination
- Tracking: DyLy can track clicks, user agents, and referrers (if enabled)
- Any Destination: Redirect to any valid URL on the internet
- Preserves Context: Query parameters and fragments can be preserved or modified
Use Cases
Marketing & Analytics:
- Shorten long campaign URLs for social media posts
- Track click-through rates across different channels
- Create memorable links for offline marketing (billboards, print ads)
- A/B testing different landing pages
User Experience:
- Simplify complex URLs with many parameters
- Create human-readable links for documentation
- Replace auto-generated URLs with branded short links
- Reduce character count for SMS or Twitter
Operations:
- Redirect old URLs to new locations after site restructuring
- Create temporary redirects for events or promotions
- Centralize link management across multiple platforms
Example API Request
POST /url/api/v1/links
{
"type": "url",
"projectId": "your-project-id",
"destinationUrl": "https://example.com/products/awesome-product?utm_source=social&utm_campaign=spring2024",
"path": "spring-sale",
"expiresIn": 2592000
}
Response:
{
"shortUrl": "https://myapp.dyly.dev/spring-sale",
"destinationUrl": "https://example.com/products/awesome-product?utm_source=social&utm_campaign=spring2024",
"expiresAt": "2024-05-01T00:00:00Z",
...
}
Best Practices
✅ Use Descriptive Paths: For user-facing links, choose memorable paths
✅ Set Appropriate Expiration: Marketing links often need longer expiration than temporary shares
✅ Monitor Analytics: Track link performance to measure campaign effectiveness
✅ Test Destinations: Ensure the destination URL is correct before distributing the short link
Tip: URL links can be created from both the portal UI and the API, making them the most accessible link type.
JSON Link
JSON links return structured JSON data instead of redirecting. They act as static API endpoints, perfect for configuration files, metadata, or any structured data.
How It Works
- User or application requests the link (e.g.,
https://myapp.dyly.dev/api/config) - DyLy server receives the request and validates the link
- Server responds with HTTP 200 OK and the registered JSON as the response body
Content-Type: application/jsonheader is automatically set
Key Features
- Static Endpoints: Create API-like endpoints without backend infrastructure
- No Database Required: Store configuration or metadata directly in DyLy
- Versioning: Create different paths for different versions (e.g.,
/v1/config,/v2/config) - Standard JSON: Any valid JSON structure is supported
Use Cases
Well-Known Endpoints:
.well-known/apple-app-site-associationfor Apple Universal Links.well-known/assetlinks.jsonfor Android App Links.well-known/openid-configurationfor OAuth/OIDC discovery.well-known/security.txtfor security contact information
Configuration & Metadata:
- App configuration that can be updated without app releases
- Feature flags and remote configuration
- Public metadata about your service or API
- Static API responses for testing or demos
Data Sharing:
- Public datasets or reference data
- Shared team configurations
- Standard response templates
- API mock endpoints for development
Example API Request
POST /url/api/v1/links
{
"type": "json",
"projectId": "your-project-id",
"path": ".well-known/apple-app-site-association",
"jsonContent": {
"applinks": {
"apps": [],
"details": [
{
"appIDs": ["TEAM123.com.example.app"],
"paths": ["*"]
}
]
}
}
}
When accessed, the link returns:
HTTP/1.1 200 OK
Content-Type: application/json
{
"applinks": {
"apps": [],
"details": [
{
"appIDs": ["TEAM123.com.example.app"],
"paths": ["*"]
}
]
}
}
Limitations
- Maximum JSON size: Check current limits in the API documentation
- No dynamic content - JSON is static once created
- To update content, you must update the link via API or create a new one
Best Practices
✅ Validate JSON: Ensure your JSON is valid before creating the link
✅ Use Specific Paths: Follow conventions for well-known endpoints
✅ Version Your Endpoints: Use paths like /v1/config for future compatibility
✅ Document Schema: Provide documentation for the JSON structure you're serving
Developer Tip: JSON links are perfect for microservices architecture where you need simple, stateless data endpoints without spinning up additional infrastructure.
JSON Web Token (JWT) Link
JWT links return cryptographically signed JSON data as a JWT (JSON Web Token). This ensures data integrity and authenticity, making them ideal for secure data exchange.
How It Works
JWT links can work in three different flows, depending on your security and application requirements:
Flow 1: Direct JWT Response
- User or application requests the link
- DyLy returns the JWT directly as the response body
- Consumer validates the JWT signature using the public JWKS
Best for: Server-to-server communication, request_uri parameters
Flow 2: Redirect - Implicit (Fragment-Based)
- User clicks the link in a browser
- DyLy redirects to
destinationUrl#jwt=<token> - Client-side JavaScript extracts the JWT from the URL fragment
- Application validates and uses the JWT
Best for: Single Page Applications (SPAs), client-side apps
Flow 3: Redirect - Code (Authorization Code)
- User clicks the link
- DyLy redirects to
destinationUrl?code=<authorization-code>&state=<state> - Backend exchanges the code for the JWT using Client ID/Secret or PKCE
- Application validates and uses the JWT
Best for: Web apps with backends, mobile apps, any OAuth 2.0-style flow
JWT Structure & Claims
DyLy automatically includes standard claims in every JWT:
Default Claims (automatically added, cannot be overwritten):
- iss (Issuer): Set to your link's domain (e.g.,
myapp.dyly.dev) - iat (Issued At): UTC timestamp when the JWT was generated
- exp (Expiration): UTC timestamp when the JWT expires
- nbf (Not Before): UTC timestamp before which the JWT is invalid
- jti (JWT ID): Unique identifier for this specific JWT
Custom Claims: You can add any additional claims in the jwtClaims field:
{
"jwtClaims": {
"sub": "user-123",
"email": "user@example.com",
"role": "admin",
"nonce": "random-nonce-value"
}
}
Signature & Verification
Signing:
- DyLy signs all JWTs using industry-standard algorithms (RS256)
- Signing keys are securely managed by DyLy - you don't need to manage keys
- Each project has its own signing keys for isolation
Verification:
- Public keys are available at
https://<your-domain>/jwks.json - Use standard JWT libraries to verify signatures (e.g.,
jsonwebtokenin Node.js,PyJWTin Python) - Always verify the signature before trusting JWT contents
Use Cases
Passwordless Authentication:
- Magic links for login (see Magic Link tutorial)
- Email verification links
- Password reset flows
Secure Data Transfer:
- Delivering signed configuration or metadata
- Transferring user claims between systems
- Signed invitations or access tokens
OAuth 2.0 & OpenID Connect:
request_uriparameter in RFC9101- Custom authentication flows
- Federation between services
State Validation (CSRF Protection)
When using redirect flows (Implicit or Code), you should use the state validation API to prevent CSRF attacks.
How It Works:
- When a user clicks the JWT link, DyLy sets a session cookie and generates a
stateparameter - The
stateis included in the redirect URL - Your application calls the state validation API with the
statevalue - DyLy verifies the state matches the session cookie
- If valid, you can proceed with confidence that the request is legitimate
State Validation API:
GET https://<your-domain>/state-validation?state=<state>&clientId=<clientId>&alias=<alias>
Cookie: <session-cookie-automatically-included>
Response:
{
"cookieValidation": "VALID",
"clickedAt": "2024-03-15T10:30:00Z",
"userAgent": "Mozilla/5.0...",
"ipAddress": "192.168.1.1"
}
Important: State validation must be called from the browser (where the cookie exists), not from your backend server. For mobile apps, ensure cookies are preserved across the authentication flow.
Alternative Validation: If cookie-based validation isn't feasible, the response metadata (IP address, user agent, timestamp) can be used for heuristic validation, though this provides weaker security guarantees.
Example API Request (Code Flow with PKCE)
POST /url/api/v1/links
{
"type": "jwt",
"projectId": "your-project-id",
"flow": "code",
"clientType": "public",
"destinationUrl": "https://yourapp.com/auth/callback",
"jwtClaims": {
"sub": "user-12345",
"email": "user@example.com",
"role": "member"
},
"jwtExpiresIn": 300,
"expiresIn": 3600,
"oneTime": true,
"keyProtected": true
}
Response:
{
"shortUrl": "https://myapp.dyly.dev/abc123?key=secret456",
"flow": "code",
"clientType": "public",
"codeVerifier": "save-this-securely",
...
}
Later, exchange the code for JWT:
POST https://dyly-api.lilacwells.com/url/api/v1/links/{alias}/jwt
Content-Type: application/x-www-form-urlencoded
code=<code-from-redirect>&client_id=<clientId>&clientType=public&codeVerifier=<saved-verifier>
Security Considerations
⚠️ Implicit Flow Risk: The implicit flow (fragment-based) exposes the JWT in the URL fragment. While fragments aren't sent to servers, they may appear in browser history or logs. Use with caution and only for appropriate use cases.
⚠️ Code Flow Recommended: For sensitive data, use the code flow with client authentication (confidential) or PKCE (public clients).
⚠️ Short JWT Expiration: Set jwtExpiresIn to the minimum time needed (e.g., 5 minutes) to reduce the window of exposure if a JWT is compromised.
⚠️ Always Verify Signatures: Never trust JWT contents without verifying the signature against the JWKS.
✅ Use State Validation: Always implement state validation in redirect flows to prevent CSRF attacks.
✅ Combine Security Features: Use oneTime: true and keyProtected: true for maximum security in sensitive flows.
Best Practices
✅ Choose the Right Flow: Direct for server-to-server, Code for web/mobile apps, Implicit only when necessary
✅ Minimize JWT Lifetime: Set jwtExpiresIn as short as practical
✅ Validate Everything: Always verify JWT signatures and check all claims (exp, nbf, iss, etc.)
✅ Use PKCE for Public Clients: Mobile apps and SPAs should use PKCE instead of client secrets
✅ Implement State Validation: Protect against CSRF with proper state validation
✅ Monitor Usage: Track JWT link usage for security auditing
Deep Link
Deep links seamlessly bridge web and mobile experiences by launching your mobile app directly from a web URL, optionally navigating to specific in-app screens.
How It Works
When App is Installed:
- User clicks the deep link (e.g.,
https://myapp.dyly.dev/product/123) - Operating system intercepts the request (via Universal Links on iOS or App Links on Android)
- OS launches your app instead of opening the browser
- App receives the URL and routing information
- App navigates to the appropriate screen (e.g., product detail page)
When App is NOT Installed:
- User clicks the deep link
- Browser opens and requests the URL from DyLy
- DyLy sets a deferred deep link cookie
- DyLy redirects to
destinationUrl(typically your app store page) - User downloads and installs the app
- On first launch, app calls the deferred parameters endpoint
- DyLy returns the original deep link parameters
- App navigates to the intended screen
Required Setup
To use deep links, you must first configure well-known endpoints:
For iOS (Universal Links):
Create a JSON link at .well-known/apple-app-site-association:
{
"applinks": {
"apps": [],
"details": [
{
"appIDs": ["TEAM123.com.example.app"],
"paths": [
"NOT /_/*",
"NOT /deferred-params",
"/*"
]
}
]
}
}
For Android (App Links):
Create a JSON link at .well-known/assetlinks.json:
[{
"relation": ["delegate_permission/common.handle_all_urls"],
"target": {
"namespace": "android_app",
"package_name": "com.example.app",
"sha256_cert_fingerprints": ["14:6D:E9:83:..."]
}
}]
Important: Add
"NOT /deferred-params"to your paths to prevent the app from launching when calling the deferred parameters API.
Deferred Deep Linking
Deferred deep linking allows you to preserve link context even when the app isn't installed at click time.
How It Works:
- DyLy sets a cookie when the link is clicked
- After app installation, app calls
/deferred-params?clientId=<clientId> - DyLy matches the request to the original click using:
- Cookie (highest confidence)
- IP address + User Agent (fallback)
- Returns the deep link token with a matching confidence score
API Request:
GET https://<your-domain>/deferred-params?clientId=<clientId>
Cookie: <automatically-included-if-browser>
Response:
{
"token": "eyJhbGci...",
"matchingScore": 0.95
}
Matching Score Interpretation:
- 1.0: Cookie match - highest confidence, safe to use
- 0.8-0.99: Strong IP/UA match - likely correct, use with caution
- 0.6-0.79: Weak IP/UA match - low confidence, consider not using
- less than 0.6: No match found - DyLy returns 404
Token Validation
The token returned in deep links and deferred parameters contains:
- Your custom
jwtClaims(set when creating the link) - Link metadata (domain, path)
- Standard JWT claims (iss, exp, etc.)
Your app must verify:
- ✅ JWT signature (using JWKS from
https://<your-domain>/.well-known/jwks.json) - ✅
issclaim matches your domain - ✅
exphasn't passed (token not expired) - ✅ Custom claims match expected values
Use Cases
User Invitations:
- Friend referral links that open to a specific group or feature
- Team invitation links with pre-filled information
- Content sharing that opens directly to shared content
Marketing Campaigns:
- App install campaigns with deep links to promoted products
- QR codes on physical products that open product details
- Email campaigns that deep link to specific app screens
Customer Support:
- Help articles that deep link to relevant settings
- Troubleshooting links that open diagnostic screens
- Account recovery flows
E-Commerce:
- Product links from web to app
- Cart recovery links
- Order tracking that opens in app
Example API Request
POST /url/api/v1/links
{
"type": "deep",
"projectId": "your-project-id",
"path": "products/awesome-widget",
"destinationUrl": "https://apps.apple.com/app/yourapp/id123456",
"jwtClaims": {
"productId": "awesome-widget",
"campaignId": "spring-2024",
"referrerId": "user-789"
},
"jwtExpiresIn": 300,
"expiresIn": 2592000,
"keyProtected": false,
"oneTime": false
}
Response:
{
"shortUrl": "https://myapp.dyly.dev/products/awesome-widget",
"type": "deep",
"jwtClaims": {
"productId": "awesome-widget",
"campaignId": "spring-2024",
"referrerId": "user-789"
},
...
}
DyLy vs. Firebase Dynamic Links
DyLy provides a modern alternative to Firebase Dynamic Links (which is being sunset):
| Feature | Firebase Dynamic Links | DyLy Deep Links |
|---|---|---|
| SDK Required | Yes | No - API only |
| Deferred Deep Linking | Yes | Yes |
| JWT Signed Tokens | No | Yes |
| Custom Domains | Yes | Yes (Paid Plan) |
| Link Expiration | No | Yes |
| One-Time Links | No | Yes (Paid Plan) |
| Protected Links | No | Yes (Paid Plan) |
| Server-Side Only | No | Yes |
| Status | Deprecated | Active & Supported |
Security Considerations
✅ Always Validate Tokens: Never trust deep link parameters without verifying JWT signatures
✅ Check Matching Score: For deferred deep links, only use high-confidence matches (≥0.9)
✅ Implement Timeouts: Reject deferred parameters that are too old
✅ Validate Claims: Ensure custom claims contain expected values and types
✅ User Confirmation: For sensitive actions, ask for user confirmation even with valid deep links
⚠️ Phishing Risk: Educate users about legitimate deep link domains to prevent phishing
⚠️ Preview/Prefetch: Be aware that link previews may consume one-time links unintentionally
Best Practices
✅ Test Both Paths: Test with app installed and app not installed scenarios
✅ Fallback Gracefully: Always provide a good destination URL (app store or mobile web)
✅ Include Context: Use jwtClaims to pass necessary routing and personalization data
✅ Monitor Metrics: Track deep link performance, install attribution, and conversion rates
✅ Handle Errors: Implement error handling for expired links, invalid tokens, or network issues
Choosing the Right Link Type
| Use Case | Recommended Link Type | Why? |
|---|---|---|
| URL Shortening | URL Link | Simple redirect, easiest to set up |
| App Configuration | JSON Link | Static data without backend infrastructure |
| Universal/App Links Setup | JSON Link | Required for well-known endpoints |
| Passwordless Login | JWT Link | Cryptographic security with signatures |
| Invitation System | Deep Link or JWT Link | Deep Link for mobile, JWT for web |
| Password Reset | JWT Link | Secure, verifiable, one-time use |
| Marketing Campaign | URL Link | Simple tracking and analytics |
| Mobile App Launch | Deep Link | Seamless app integration |
| OAuth request_uri | JWT Link (Direct) | Standard-compliant signed requests |
Next Steps
Now that you understand the different link types:
- Review Core Features: Learn about expiration, protection, and other features that apply to all link types
- Follow Tutorials: See real-world implementations in Use Cases
- API Reference: Dive deep into the complete API documentation
Start Simple: Begin with URL links to get familiar with DyLy, then explore more advanced link types as your needs evolve.