Skip to content

Commit 4842530

Browse files
authored
Merge pull request #124 from DefGuard/blog/mfa-isnt-an-addon
2 parents 45033f3 + 4383fa7 commit 4842530

File tree

3 files changed

+129
-6
lines changed

3 files changed

+129
-6
lines changed

src/content/blog/mfa-isnt-an-addon.mdx renamed to src/content/blog/fortitoken-alternative-vpn-mfa.mdx

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
---
1+
---
22
title: "Security shouldn't cost extra — MFA isn't an add-on"
3+
seoTitle: "FortiToken Alternative: Why Legacy VPNs Overcharge for MFA"
34
publishDate: 2025-11-05
4-
description: "MFA is mandatory under frameworks like NIS2. See why legacy VPNs sell it as an add-on, how that creates cost and risk, and how Defguard builds it in by default."
5+
description: "Stop paying the 'security tax.' Legacy VPNs like Fortinet treat MFA as a costly add-on. See how Defguard's built-in MFA (a FortiToken alternative) meets NIS2."
56
author: "Robert (Co-Founder, Defguard)"
67
image: "/images/blog/mfa-isnt-an-addon/mfa-hero.png"
8+
draft: true
79
---
810

911
![Security shouldn't cost extra — MFA isn't an add-on](/images/blog/mfa-isnt-an-addon/mfa-hero.png)
@@ -131,8 +133,8 @@ Yes. Defguard, as a modern WireGuard®-based platform, includes MFA by default
131133
"@graph": [
132134
{
133135
"@type": "BlogPosting",
134-
"headline": "Security shouldn't cost extra — MFA isn't an add-on",
135-
"description": "MFA is mandatory under frameworks like NIS2. Learn why legacy VPNs sell it as an add-on and how Defguard builds it in by default.",
136+
"headline": "FortiToken Alternative: Why Legacy VPNs Overcharge for MFA",
137+
"description": "Stop paying the security tax. Legacy VPNs like Fortinet treat MFA as a costly add-on. See how Defguard's built-in MFA meets NIS2 compliance.",
136138
"image": "https://defguard.net/images/blog/mfa-isnt-an-addon/mfa-hero.png",
137139
"author": {
138140
"@type": "Person",
@@ -154,7 +156,7 @@ Yes. Defguard, as a modern WireGuard®-based platform, includes MFA by default
154156
"datePublished": "2025-11-05",
155157
"mainEntityOfPage": {
156158
"@type": "WebPage",
157-
"@id": "https://defguard.net/blog/mfa-isnt-an-addon/"
159+
"@id": "https://defguard.net/blog/fortitoken-alternative-vpn-mfa/"
158160
},
159161
"articleSection": "Security, VPN, MFA, WireGuard",
160162
"keywords": ["MFA", "FortiToken", "WireGuard", "NIS2", "VPN", "Defguard", "SSO", "IdP"]
@@ -199,3 +201,4 @@ Yes. Defguard, as a modern WireGuard®-based platform, includes MFA by default
199201
]
200202
}`}
201203
</script>
204+

src/content/config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { defineCollection, z } from "astro:content";
44
// Schema definitions
55
const blogSchema = z.object({
66
title: z.string(),
7+
seoTitle: z.string().optional(),
78
publishDate: z.date(),
89
description: z.string(),
910
draft: z.boolean().optional().default(false),

src/pages/blog/[slug].astro

Lines changed: 120 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ const formatDate = (date: Date) => {
2828
});
2929
};
3030
31-
const title = `${entry.data.title} | Defguard Blog`;
31+
const title = `${entry.data.seoTitle || entry.data.title} | Defguard Blog`;
3232
const description = entry.data.description;
3333
const url = `https://defguard.net/blog/${entry.slug}`;
3434
@@ -162,8 +162,74 @@ const hasCaseStudy =
162162
</main>
163163

164164
<MoreStories currentSlug={entry.slug} posts={allPosts} />
165+
166+
<!-- Image Lightbox -->
167+
<div id="image-lightbox" class="lightbox">
168+
<span class="lightbox-close">&times;</span>
169+
<img class="lightbox-content" id="lightbox-img" alt="" />
170+
<div class="lightbox-caption" id="lightbox-caption"></div>
171+
</div>
165172
</ProductLayout>
166173

174+
<script>
175+
// Image lightbox functionality
176+
document.addEventListener('DOMContentLoaded', () => {
177+
const lightbox = document.getElementById('image-lightbox');
178+
const lightboxImg = document.getElementById('lightbox-img') as HTMLImageElement;
179+
const lightboxCaption = document.getElementById('lightbox-caption');
180+
const closeBtn = document.querySelector('.lightbox-close');
181+
182+
// Get all images in post content (excluding hero images in header)
183+
const postContent = document.querySelector('.post-content');
184+
if (postContent) {
185+
const images = postContent.querySelectorAll('img');
186+
187+
images.forEach((img) => {
188+
// Add cursor pointer to indicate clickable
189+
img.style.cursor = 'pointer';
190+
191+
img.addEventListener('click', () => {
192+
if (lightbox && lightboxImg && lightboxCaption) {
193+
lightbox.style.display = 'flex';
194+
lightboxImg.src = img.src;
195+
lightboxImg.alt = img.alt;
196+
lightboxCaption.textContent = img.alt || '';
197+
// Prevent body scroll when lightbox is open
198+
document.body.style.overflow = 'hidden';
199+
}
200+
});
201+
});
202+
}
203+
204+
// Close lightbox
205+
const closeLightbox = () => {
206+
if (lightbox) {
207+
lightbox.style.display = 'none';
208+
document.body.style.overflow = 'auto';
209+
}
210+
};
211+
212+
if (closeBtn) {
213+
closeBtn.addEventListener('click', closeLightbox);
214+
}
215+
216+
if (lightbox) {
217+
lightbox.addEventListener('click', (e) => {
218+
if (e.target === lightbox) {
219+
closeLightbox();
220+
}
221+
});
222+
}
223+
224+
// Close on ESC key
225+
document.addEventListener('keydown', (e) => {
226+
if (e.key === 'Escape') {
227+
closeLightbox();
228+
}
229+
});
230+
});
231+
</script>
232+
167233
<style lang="scss">
168234
// Removed global overflow overrides that were interfering with sticky positioning
169235

@@ -545,4 +611,57 @@ const hasCaseStudy =
545611
}
546612
}
547613
}
614+
615+
/* Image Lightbox Styles */
616+
.lightbox {
617+
display: none;
618+
position: fixed;
619+
z-index: 9999;
620+
left: 0;
621+
top: 0;
622+
width: 100%;
623+
height: 100%;
624+
background-color: rgba(0, 0, 0, 0.95);
625+
justify-content: center;
626+
align-items: center;
627+
flex-direction: column;
628+
padding: 20px;
629+
630+
.lightbox-content {
631+
max-width: 95%;
632+
max-height: 85vh;
633+
width: auto;
634+
height: auto;
635+
object-fit: contain;
636+
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
637+
border-radius: 4px;
638+
margin: 0;
639+
}
640+
641+
.lightbox-close {
642+
position: absolute;
643+
top: 20px;
644+
right: 40px;
645+
color: #fff;
646+
font-size: 48px;
647+
font-weight: 300;
648+
cursor: pointer;
649+
transition: color 0.2s ease;
650+
line-height: 1;
651+
user-select: none;
652+
653+
&:hover {
654+
color: var(--primary-button-bg, #0c8ce0);
655+
}
656+
}
657+
658+
.lightbox-caption {
659+
color: #fff;
660+
text-align: center;
661+
padding: 15px;
662+
max-width: 800px;
663+
font-size: 16px;
664+
margin-top: 15px;
665+
}
666+
}
548667
</style>

0 commit comments

Comments
 (0)