avatarAugust Birch

Free AI web copilot to create summaries, insights and extended knowledge, download it at here

5810

Abstract

div id="2fc2"><pre>npm install express express-session keycloak-connect nodemon</pre></div><h2 id="592f">Define main execution file — app.js</h2><p id="f128">Add a file named app.js at the root level of your secure-express-service project.</p><p id="8d46">Define imports and express app</p><div id="54ca"><pre><span class="hljs-comment">// file - app.js</span>

<span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express'</span>); <span class="hljs-keyword">const</span> session = <span class="hljs-built_in">require</span>(<span class="hljs-string">"express-session"</span>); <span class="hljs-keyword">const</span> <span class="hljs-title class_">Keycloak</span> = <span class="hljs-built_in">require</span>(<span class="hljs-string">"keycloak-connect"</span>);

<span class="hljs-keyword">const</span> app = <span class="hljs-title function_">express</span>(); <span class="hljs-keyword">const</span> <span class="hljs-variable constant_">PORT</span> = <span class="hljs-number">3000</span>;

...</pre></div><p id="ccec">Setup Keycloak Middleware</p><div id="cefb"><pre><span class="hljs-comment">// file - app.js</span>

...

<span class="hljs-keyword">const</span> <span class="hljs-variable constant_">USER_ROLE</span> = process.<span class="hljs-property">env</span>.<span class="hljs-property">USER_ROLE</span> || <span class="hljs-string">'express-user'</span>; <span class="hljs-keyword">const</span> <span class="hljs-variable constant_">ADMIN_ROLE</span> = process.<span class="hljs-property">env</span>.<span class="hljs-property">ADMIN_ROLE</span> || <span class="hljs-string">'express-admin'</span>;

<span class="hljs-keyword">const</span> kcConfig = { <span class="hljs-attr">clientId</span>: process.<span class="hljs-property">env</span>.<span class="hljs-property">AUTH_CLIENT_ID</span> || <span class="hljs-string">'secure-express-service'</span>, <span class="hljs-attr">bearerOnly</span>: <span class="hljs-literal">true</span>, <span class="hljs-attr">serverUrl</span>: process.<span class="hljs-property">env</span>.<span class="hljs-property">AUTH_SERVER</span> || <span class="hljs-string">'http://localhost:8080'</span>, <span class="hljs-attr">realm</span>: process.<span class="hljs-property">env</span>.<span class="hljs-property">AUTH_REALM</span> || <span class="hljs-string">'master'</span> };

<span class="hljs-keyword">const</span> memoryStore = <span class="hljs-keyword">new</span> session.<span class="hljs-title class_">MemoryStore</span>();

<span class="hljs-title class_">Keycloak</span>.<span class="hljs-property"><span class="hljs-keyword">prototype</span></span>.<span class="hljs-property">accessDenied</span> = <span class="hljs-keyword">function</span> (<span class="hljs-params">request, response</span>) { response.<span class="hljs-title function_">status</span>(<span class="hljs-number">401</span>) response.<span class="hljs-title function_">setHeader</span>(<span class="hljs-string">'Content-Type'</span>, <span class="hljs-string">'application/json'</span>) response.<span class="hljs-title function_">end</span>(<span class="hljs-title class_">JSON</span>.<span class="hljs-title function_">stringify</span>({ <span class="hljs-attr">status</span>: <span class="hljs-number">401</span>, <span class="hljs-attr">message</span>: <span class="hljs-string">'Unauthorized/Forbidden'</span>, <span class="hljs-attr">result</span>: { <span class="hljs-attr">errorCode</span>: <span class="hljs-string">'ERR-401'</span>, <span class="hljs-attr">errorMessage</span>: <span class="hljs-string">'Unauthorized/Forbidden'</span> } })) }

<span class="hljs-keyword">const</span> keycloak = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Keycloak</span>({ <span class="hljs-attr">store</span>: memoryStore }, kcConfig);

<span class="hljs-keyword">function</span> <span class="hljs-title function_">adminOnly</span>(<span class="hljs-params">token, request</span>) { <span class="hljs-keyword">return</span> token.<span class="hljs-title function_">hasRole</span>(<span class="hljs-string">realm:<span class="hljs-subst">${ADMIN_ROLE}</span></span>); }

<span class="hljs-keyword">function</span> <span class="hljs-title function_">isAuthenticated</span>(<span class="hljs-params">token, request</span>) { <span class="hljs-keyword">return</span> token.<span class="hljs-title function_">hasRole</span>(<span class="hljs-string">realm:<span class="hljs-subst">${ADMIN_ROLE}</span></span>) || token.<span class="hljs-title function_">hasRole</span>(<span class="hljs-string">realm:<span class="hljs-subst">${USER_ROLE}</span></span>); }

app.<span class="hljs-title function_">use</span>(<span class="hljs-title function_">session</span>({ <span class="hljs-attr">secret</span>: process.<span class="hljs-property">env</span>.<span class="hljs-property">APP_SECRET</span> || <span class="hljs-string">'BV&%R*BD66JH'</span>, <span class="hljs-attr">resave</span>: <span class="hljs-literal">false</span>, <span class="hljs-attr">saveUninitialized</span>: <span class="hljs-literal">true</span>, <span class="hljs-attr">store</span>: memoryStore }));

app.<span class="hljs-title function_">use</span>( keycloak.<span class="hljs-title function_">middleware</span>() );

...</pre></div><p id="bfe2">Setup REST endpoint and server</p><div id="5fc0"><pre>app.<span class="hljs-title function_">get</span>(<span class="hljs-string">'/public'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =></span> { res.<span class="hljs-title function_">status</span>(<span class="hljs-number">200</span>).<span class="hljs-title function_">send</span>({ <span class="hljs-string

Options

">'message'</span>: <span class="hljs-string">"This is a public enpoint which can be accessed by anonymous users"</span>, }); })

app.<span class="hljs-title function_">get</span>(<span class="hljs-string">'/secured'</span>, [keycloak.<span class="hljs-title function_">protect</span>(isAuthenticated)], <span class="hljs-function">(<span class="hljs-params">req, res</span>) =></span> { res.<span class="hljs-title function_">status</span>(<span class="hljs-number">200</span>).<span class="hljs-title function_">send</span>({ <span class="hljs-string">'message'</span>: <span class="hljs-string">"This is a secured enpoint which can be accessed by any authenticated user"</span>, }); })

app.<span class="hljs-title function_">get</span>(<span class="hljs-string">'/secured-admin'</span>, [keycloak.<span class="hljs-title function_">protect</span>(adminOnly)], <span class="hljs-function">(<span class="hljs-params">req, res</span>) =></span> { res.<span class="hljs-title function_">status</span>(<span class="hljs-number">200</span>).<span class="hljs-title function_">send</span>({ <span class="hljs-string">'message'</span>: <span class="hljs-string">"This is a secured enpoint which can be accessed only by any authenticated user with role admin"</span>, }); })

app.<span class="hljs-title function_">listen</span>(<span class="hljs-variable constant_">PORT</span>, <span class="hljs-function">(<span class="hljs-params">error</span>) =></span> { <span class="hljs-keyword">if</span> (!error) { <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">"Server is Successfully Running, and App is listening on port "</span> + <span class="hljs-variable constant_">PORT</span>) } <span class="hljs-keyword">else</span> { <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">"Error occurred, server can't start"</span>, error); } } );</pre></div><h2 id="a530">Update package.json scripts to run server</h2><ul><li>Update the content in the <b>scripts </b>section of <b>package.json</b> as below. It will help you run your express server in both development and production mode</li></ul><div id="6d0e"><pre> <span class="hljs-attr">"scripts"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span> <span class="hljs-attr">"start"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"node app.js"</span><span class="hljs-punctuation">,</span> <span class="hljs-attr">"dev"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"nodemon app.js"</span> <span class="hljs-punctuation">}</span><span class="hljs-punctuation">,</span></pre></div><ul><li>Start your express server in development mode(auto-reload on file change) using the below command</li></ul><div id="464c"><pre>npm run dev</pre></div><h1 id="1699">Testing your REST APIs</h1><h2 id="f8a6">Public Endpoint— http://localhost:3000/public</h2><ul><li>Even without an authentication token, this endpoint will fetch a response.</li></ul><figure id="74df"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*xjvkOCdQJ5VIolwBtu-TWg.png"><figcaption></figcaption></figure><h2 id="f796">Secured Endpoint — http://localhost:3000/secured</h2><ul><li>Without a token, you should get an authentication error</li></ul><figure id="ad69"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*rSANl9_J1BRma6p1UjgLPg.png"><figcaption></figcaption></figure><ul><li>Let’s set up the <b>Authorization</b> tab to generate a token using the <b>Configure New Token </b>section. You can use the values below.</li></ul><div id="3d60"><pre>Token <span class="hljs-type">Name</span> - secure-express-service <span class="hljs-keyword">Grant</span> <span class="hljs-keyword">type</span> - <span class="hljs-keyword">Password</span> Credentials <span class="hljs-keyword">Access</span> Token URL - http://localhost:<span class="hljs-number">8080</span>/realms/master/protocol/openid-<span class="hljs-keyword">connect</span>/token Client ID - secure-express-service Username - <span class="hljs-keyword">user</span>@nerdcore.com <span class="hljs-keyword">Password</span> - Client Authentication - Send <span class="hljs-keyword">as</span> basic auth <span class="hljs-keyword">header</span></pre></div><figure id="5d0e"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*AEhl6BHxVPT5J6X6wKnxGg.png"><figcaption></figcaption></figure><ul><li>Click on <b>Get New Access Token</b>, then P<b>roceed</b>, then <b>Use Token</b></li></ul><figure id="ea60"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*t7pdQRYhqsnhK_NDBSD19g.png"><figcaption></figcaption></figure><figure id="55e0"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*MwMrf1npagIRpGmXEfOWcw.png"><figcaption></figcaption></figure><ul><li>Now fire the <b>/secured</b> rest endpoint again, and you will get a successful response.</li></ul><figure id="e106"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*xsq6E7TWbMeTHXzNEQMD1Q.png"><figcaption></figcaption></figure><h2 id="97a4">Secured Admin Endpoint — http://localhost:3000/secured-admin</h2><ul><li>If you try to access the endpoint without any token — Auth error</li><li>If you try to access the endpoint with the token from [email protected] — Auth error</li><li>If you try to access the endpoint with the token from [email protected] — Success</li></ul><p id="db11">You can find the GitHub repository <a href="https://github.com/saurav-samantray/secure-express-service">here</a> for reference.</p><p id="eda2">Happy learning and happy coding!</p></article></body>

My Unconventional, Autopilot Email Strategy for Writers and Creators

This isn’t your grandmother’s 7-step recipe, but it works

Photo by Adam Johnson on Unsplash

Yesterday, one reader gave me a challenge in the comments of a story I wrote. I write a lot about the importance of list-building, but I don’t always share what to do once a writer has built said list (or even how to build a list in the first place).

So, I figured I’d give a high-level view of my tricks, tips, and strategies.

**This is one you may want to bookmark**

This story isn’t everything I know about email (that wouldn’t be fair to paying customers), but it’s enough to make a writer dangerous. I learn more about email daily. But these strategies have worked well for me over the past 20+ years I’ve been doing email marketing for various business ventures.

Email is the highest-grossing app you’ve got in your pocket.

Although email is the old man of marketing vehicles, it’s 20+ year history makes it older than social media. And definitely older and more-reliable than all the flashy stuff you see on the YouTubes.

There are something like 2–3 billion Facebook accounts. Cool…. but there are six billion email accounts. Social comes and goes, but people hold onto their email addresses like Papa’s antiques.

Email is really hard to dump.

I’ve tried it multiple times and I end up using both my new email address and my old one. I can never quite delete the old one completely. There’s always the fear that one, long-lost person still has the old address.

This is good news for us creators.

Email isn’t going anywhere and it’s one of the last level playing fields. Once you have a reader on your list you can contact her whenever you choose. You know if you send an email there’s a 98% chance your email will land in her in-box.

With social, we’ve got to pay to play. With email, you pay for your list size. You can send as many emails as you wish. Contact is almost free.

Here, we’ll use the principles of direct marketing. Many of these are the same as the strategies used for direct mail. We send targeted content to the people we serve. The targeted content benefits the reader, not the writer. And we ask the reader to perform a single action in each email.

I use email for both my fiction and non-fiction writing.

Although my fiction took a back seat over the past couple years, it’s not dead. Whether you’re a writer or creator, you need an email list. Email is the last great equalizer in marketing.

You can compete with Fortune 100 businesses for the same share of your reader’s in-box without paying a dime in advertising. I don’t know of any other marketing channel where that’s still possible.

Some of my statements in this story might hurt your feelings.

This is a process that works for me. It might work for you if you’re open to it. There’s a good change your current email gathering process could use an oil change. And that’s what we’re here to do today.

Let’s get started.

How I use email to build my publishing business

The email process starts way before you send a single letter. My process begins with content marketing. A whole crap-ton of it. I’ve written over 800 Medium stories to date in a little over a year, and every single one of those stories goes to work for me.

1. We begin with targeted, niche content —

You can pay for ads to earn new readers. As you grow your business, you should. But for most writers and creators content marketing is a great place to start.

Medium will pay you to acquire new leads. This is how I use this platform. I chose a target niche to serve (writers and creators who want to sell more of their work) and I write everything to serve those people and no one else.

I use my content to build a tribe of like-minded creatives. Some of those people appreciate my content and join my email list.

Content is very important, because it works over time. I’ve had subscribers that took up to six months of my content (maybe 300 stories) to finally convince them to join my tribe. Think of how expensive that would be with ads. Every story I write has a call to action at the bottom, to join my tribe.

Stop blogging.

No one care about your blog. You’ll have much better luck posting those same articles on sites where the readers are already gathered in large numbers. I blogged for a decade. I’ll never do it again.

Unless you already have hundreds of thousands of readers on your site, you time is much better spent posting lead-generating article on sites with huge followings.

We just don’t care about blogs anymore.

We used to. For a bit, the internet would find our content. Now it prefers content on these bigger platforms. Remember the purpose of your content — to generate more email subscribers.

If you want to keep a blog for vanity reasons, so be it. But if you want to build a tribe, blogging is a slow-road to a ton of work that will lead to very little results.

Sure, re-post your stories on your blog if you want, but that should not be your primary source of leads.

2. We then move to an irresistible offer —

Your offer is different than my offer. I get asked “what should I create for a free offer” all the time and I ignore most of those request. We must make a targeted, valuable, free offer that attracts the people we want in our tribe.

In my case, I offer a 7-day email masterclass.

Your offer will be totally different. But there’s one thing in common, we’ve got to make an offer worth paying-for, an offer that transforms the reader from where she is now to where she wants to be, and an offer she can’t get anywhere else (not easily, at least).

Instead of worrying about what makes a great offer, let’s focus on what makes a terrible offer (I call the free offer an Easy Invite).

How to make a terrible Easy Invite:

  • Ask readers to “sign up here to stay in touch”
  • Ask readers to “join my newsletter”
  • Ask readers to “sign-up for my email list”

These are the three most-common and the least possible attractive lead magnets you could offer. You’d probably do better to have a sign-up page with no text at all, versus one of these three travesties.

Why?

We’re sick and tired of ‘newsletters.’ Newsletters are self-serving for the business. We want content the only benefits us.

No one wants to be on some list. You can call your email list a list when you’re in like company, but if you’re speaking to your tribe, it’s crazy to ask people to ‘join your list.’ You don’t want to be on some list. I don’t want to be on some list. Your readers don’t want to be on some list.

We want to feel as if you’re talking to us, individually.

What makes a successful Easy Invite:

  • Full e-books (not free chapters, that only works for NYT famous authors)
  • Valuable blueprints (not just empty sales pitches)
  • Mini-courses
  • Anything we’d be willing to pay actual money for (if your EA isn’t worth actual cash, you didn’t try hard enough. We’ve got to sell FREE just as hard as the paid stuff).

3. We then build a landing page that converts clickers into subscribers —

Again, your landing page will be different than my landing page. You will make hundreds of iterations, changing headlines, colors, images, button colors, and text-order until you can convert the highest number of visitors.

Not everyone who clicks your article link will subscribe to your list. Most won’t. It’s the way the game works. Through testing, tweaking, and adjusting we can increase the number of folks who do join our list.

Your landing page is not your website.

A landing page has a binary purpose — subscribe or leave. There’s no ‘about me’ link or a bunch of stories or contact information. Save all that for your actual website. A landing page is a separate web page whose sole mission in life is to grow your email list.

There’s one decision to make (subscribe or not). If your landing page requires more than one decision, it’s not a landing page.

4. We write an automated welcome sequence —

You can write a single email to a hundred emails. There are writers who have a couple years of content pre-loaded in their email service provider (ESP).

Your welcome sequence helps the reader know who you are, why she should trust you, what she can expect from the relationship (how often you’ll make offers and how often you’ll email), and how you’ll solve her problems.

How often?

Once a week, minimum. Twice is better. There are people who email daily. Some, multiple times a day. We train our readers early to expect a certain level of contact from us.

If your emails are good, they’ll open them even if you email daily.

I know a guy whose entire seven-figure business involves sending one email every morning, then going about his day doing whatever he wants.

What do I write?

Write valuable, entertaining content. We call this infotainment. No one wants a lecture. No one wants cat videos every day. We want up-beat, informative stuff, written in a unique voice that solves a unique problem in our lives.

You must know your customer.

Write in a conversational voice, to one person at a time. Never address your list like a group. Picture your mother across the kitchen table from you. Have a conversation with her.

I get direct replies from people daily.

Many of these readers thought I emailed them that morning — just them. Even though I wrote the email two years ago.

I’ve had comments that my emails are too long, or not professional enough. I take these as great compliments. You don’t want to send corporate emails. No one opens or reads those. Corporate emails are to keep the people who send them employed.

If you want to write emails that engage and sell, you’ve got to write to a close friend and adjust your tone and language accordingly. You know your audience. Write to them in a way they’ll respond.

5. We use only one ask per email —

Every email should do one thing. Whether you want the reader to click an article, reply with an answer, take a survey, buy something, or even unsubscribe, each email should solicit a binary decision from the reader.

Give the reader too many choices and she’ll choose none.

Many writers and creators send these once-a-quarter or once-a-month catalog-like emails that try to cover too many options. Instead, email more-frequently and ask for one thing.

That said, every email you send should have a purpose.

Never send an email just to send one — to ‘get something out today.’ If you don’t have a purpose for sending an email, don’t send one. No one is keeping track. We don’t care about your newsletter that much.

Your subject line is critical.

If you don’t spend an inordinate amount of time tweaking your subject lines, you’re leaving money on the table. If we don’t open your emails we won’t read your content. If we don’t read your content, we wont buy your stuff.

6. We pepper our email sequence with the occasional, automated offer —

This is how we make money while we sleep. Whether it’s books, consulting, courses, coaching, hard goods etc. Every 3–5 emails you send a paid offer. This is how you keep the lights on.

Instead of live-begging your readers for money, your email sequence has a measured series of repeated offers for your work. If you don’t have anything to sell yet, sign-up for affiliate programs you endorse.

I call this mailbox money.

Every morning I check my phone and look at the money I made while I slept. Instead of trying to send one-off sales offers to my email list, I use an automated sequence. This way, my main job becomes content generation to add more writers and creators into my tribe.

7. Serve your tribe and no one else —

You want to own your niche. Go an inch-wide and a mile-deep with your content generation. You’ll get a ton of negative flack from the people you don’t serve. Ignore them. They aren’t invited.

Give your readers free content until it hurts. Then give a little more.

The landscape is ridiculously competitive. Give away almost everything. Your best readers will still pay for more access to you. Trust me, your ideas aren’t that amazing that you readers will jump-ship if they get bored or feel like you aren’t providing enough value.

I’m still working on this myself. I could always give more. You can too.

None of this is easy or fast. You’ve got to out-work your competition. You’ve got to give more and try harder. You’ve got to connect with your readers in a way they can’t get from some other Schmoe down the street.

Accomplish that, you’ve got a reader for life.

It’s time to build your email list

I don’t know about you, but I’m an introvert. I’d rather do anything than talk to people and self-promote. I want more time to write and do my work that matters most.

Email does the trick.

If you build an automated email sequence, all the hard-selling is done for you. You’ll have more time to do your best work, spending less time promoting it one-on-one.

If you’re ready to build your email list, I’ve got the solution.

I hand-crafted a free, 7-day, Tribe 1K email masterclass for you. I’ll show you how to get your first 1,000 (or your next 1,000) subscribers without spending a thin dime on ads.

Guarantee your seat and enroll today. You’ll have your first lesson before dinner tonight.

Past students include self-published indies with dozens of books to their name, New York Times bestselling writers, and creators who want to get their work before a bigger audience.

The Tribe 1K works for them. It might work for you. This isn’t some get-rich-quick thing. Most writers and creators won’t follow-through. That’s what happens with free content.

But you’re different. I can feel it. This is how you’ll stand-out among the fray.

Tap the link.

We’re waiting for you.

Enroll in my Email Masterclass. Get Your First 1,000 Subscribers

August Birch (AKA the Book Mechanic) is both a fiction and non-fiction author from Michigan, USA. As a self-appointed guardian of writers and creators, August teaches indies how to make work that sells and how to sell more of that work once it’s created. When he’s not writing or thinking about writing, August carries a pocket knife and shaves his head with a safety razor.

Email Marketing
Marketing
Writing
Marketing Strategies
Entrepreneurship
Recommended from ReadMedium