avatarZane Dickens the Instigator

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

5801

Abstract

cookie.</li><li><code>secure: true</code> ensures that the cookie is only sent over secure, encrypted connections (HTTPS). but since most testing environments are on localhost, it is allowed</li></ul><p id="6bc1">then executing this action looks like:</p><div id="e2cb"><pre><span class="hljs-keyword">import</span> { storeToken } <span class="hljs-keyword">from</span> <span class="hljs-string">"@/lib/actions"</span>;

<span class="hljs-keyword">async</span> <span class="hljs-keyword">function</span> <span class="hljs-title function_">onSubmit</span>(<span class="hljs-params">formData</span>) { <span class="hljs-title function_">setIsLoading</span>(<span class="hljs-literal">true</span>); <span class="hljs-keyword">try</span> { <span class="hljs-keyword">const</span> resp = <span class="hljs-keyword">await</span> http.<span class="hljs-title function_">post</span>(<span class="hljs-string">/auth/login</span>, formData);

  <span class="hljs-keyword">await</span> <span class="hljs-title function_">storeToken</span>(resp.<span class="hljs-property">data</span>);

  router.<span class="hljs-title function_">push</span>(<span class="hljs-string">"/dashboard"</span>);

  <span class="hljs-title function_">toast</span>({
    <span class="hljs-attr">title</span>: <span class="hljs-string">"Login Successful"</span>,
  });
} <span class="hljs-keyword">catch</span> (error) {
  <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">error</span>(<span class="hljs-string">"error logging in"</span>, error);
} <span class="hljs-keyword">finally</span> {
  <span class="hljs-title function_">setIsLoading</span>(<span class="hljs-literal">false</span>);
}

}</pre></div><p id="173a">After testing this check your cookie storage in devtools and the token should be set:</p><figure id="de3a"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*VxsyZ7KTXg_XygebpIfq1Q.png"><figcaption></figcaption></figure><p id="7f8d">Now let’s move on to using the token to communicate with our API.</p><h1 id="ad3b">2. Accessing the Token</h1><p id="3425">So accessing the token is different depending on the context. If you are accessing it on the server it looks like:</p><div id="ba24"><pre>import {cookies} <span class="hljs-keyword">from</span> <span class="hljs-string">"next/headers"</span>;

<span class="hljs-keyword">const</span> authToken = cookies().<span class="hljs-keyword">get</span>(<span class="hljs-string">"accessToken"</span>)?.<span class="hljs-keyword">value</span> </pre></div><p id="636a">In the Client side, because we set <code>httpOnly: true</code> . How do we now access our jwt? That’s where creating an api route comes in. It would have been really cool to have a server action for retrieving the token but we don’t have that yet. “fix up Next.js team”!</p><p id="dc9e">Docs for api routes using the app router <a href="https://nextjs.org/docs/app/building-your-application/routing/route-handlers">here</a></p><p id="c93d">so the gist is a folder structure of <code>app/api/auth/token/route.ts</code> resolves to an endpoint with path of <code>/api/auth/token</code> . Now in the route.ts file we write:</p><div id="916b"><pre>import { cookies } <span class="hljs-keyword">from</span> <span class="hljs-string">'next/headers'</span>

export async <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">GET</span>(<span class="hljs-params">request: Request</span>) </span>{ <span class="hljs-keyword">const</span> <span class="hljs-variable constant_">authToken</span> = <span class="hljs-title function_ invoke__">cookies</span>().<span class="hljs-title function_ invoke__">get</span>(<span class="hljs-string">'accessToken'</span>)?.value <span class="hljs-keyword">const</span> <span class="hljs-variable constant_">headers</span> = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Headers</span>(); headers.<span class="hljs-title function_ invoke__">append</span>(<span class="hljs-string">"Authorization"</span>, authToken);

<span class="hljs-keyword">const</span> <span class="hljs-variable constant_">response</span> = await <span class="hljs-title function_ invoke__">fetch</span>(`${process.env.NEXT_PUBLIC_API_URL}/user`,{
  <span class="hljs-attr">headers</span>: headers
}
<span class="hljs-keyword">if</span> (response.status === <span class="hljs-number">401</span>) {
  <span class="hljs-keyword">const</span> <span class="hljs-variable constant_">refreshPayload</span> = {
    <span class="hljs-string">"refresh_token"</span>: <span class="hljs-title function_ invoke__">cookies</span>().<span class="hljs-title function_ invoke__">get</span>(<span class="hljs-string">'refreshToken'</span>)?.value
  }
  <span class="hljs-keyword">const</span> <span class="hljs-variable constant_">res</span> = await <span class="hljs-title function_ invoke__">fetch</span>(`${process.env.NEXT_PUBLIC_API_URL}/refresh-token, {
    <span class="hljs-attr">method</span>: <span class="hljs-string">"POST"</span>,
    <span class="hljs-attr">headers</span>: {
      <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application/json"</span>,
    },
     <span class="hljs-attr">body</span>: JSON.<span class="hljs-title function_ invoke__">stringify</span>(refreshPayload),
  }
  
  <span class="hljs-keyword">const</span> jsonData = await res.<span class="hljs-title function_ invoke__">json</span>()
  
  <span class="hljs-title function_ invoke__">cookies</span>().<span class="hljs-title function_ invoke__">set</span>({
    <span class="hljs-attr">name</span>: <span class="hljs-string">"acce

Options

ssToken"</span>, <span class="hljs-attr">value</span>: jsonData.token, <span class="hljs-attr">httpOnly</span>: <span class="hljs-literal">true</span>, <span class="hljs-attr">sameSite</span>: <span class="hljs-string">"strict"</span>, <span class="hljs-attr">secure</span>: <span class="hljs-literal">true</span>, })

  <span class="hljs-title function_ invoke__">cookies</span>().<span class="hljs-title function_ invoke__">set</span>({
      <span class="hljs-attr">name</span>: <span class="hljs-string">"refreshToken"</span>,
      <span class="hljs-attr">value</span>: jsonData.refresh_token,
      <span class="hljs-attr">httpOnly</span>: <span class="hljs-literal">true</span>,
      <span class="hljs-attr">sameSite</span>: <span class="hljs-string">"strict"</span>,
      <span class="hljs-attr">secure</span>: <span class="hljs-literal">true</span>,
  })
} 
<span class="hljs-keyword">const</span> resData = {
    <span class="hljs-attr">token</span>: <span class="hljs-title function_ invoke__">cookies</span>().<span class="hljs-title function_ invoke__">get</span>(<span class="hljs-string">'accessToken'</span>)?.value
}



<span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Response</span>(JSON.<span class="hljs-title function_ invoke__">stringify</span>(resData), {
    <span class="hljs-attr">status</span>: <span class="hljs-number">200</span>,
    <span class="hljs-attr">headers</span>: {
        <span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'application/json'</span>,
    },
})

}</pre></div><p id="66db">Now let’s break down what this api route does:</p><ul><li>we retrieve the jwt from the cookie store</li><li>we make a request to /user on our api to check if the token is still valid. /user can be replaced with any protected route on your api</li><li>if we receive the <code>unauthorized(401)</code> error code we send a request to get a new token pair with our refresh token.</li><li>then we return the valid token back to the client for use.</li></ul><p id="260f">Now, to make use of this API route we can write an axios interceptor like so:</p><div id="b457"><pre>axiosInstance.<span class="hljs-property">interceptors</span>.<span class="hljs-property">request</span>.<span class="hljs-title function_">use</span>(<span class="hljs-keyword">async</span> (config) => { <span class="hljs-keyword">if</span> (config.<span class="hljs-property">url</span>?.<span class="hljs-title function_">includes</span>(<span class="hljs-string">"auth"</span>)) { <span class="hljs-keyword">return</span> config }

    <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> <span class="hljs-title function_">fetch</span>(<span class="hljs-string">'/api/auth/token'</span>)
    <span class="hljs-keyword">const</span> resData = <span class="hljs-keyword">await</span> res.<span class="hljs-title function_">json</span>()
    <span class="hljs-keyword">const</span> token = resData?.<span class="hljs-property">token</span>

    config.<span class="hljs-property">headers</span>![<span class="hljs-string">'Authorization'</span>] = <span class="hljs-string">"Bearer "</span> + token
     <span class="hljs-keyword">return</span> config
},
<span class="hljs-function">(<span class="hljs-params">error</span>) =&gt;</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-title class_">Promise</span>.<span class="hljs-title function_">reject</span>(error)
}

)</pre></div><p id="8f27">What this interceptor does is: “if the app is making a request to an auth route like <code>/auth/login</code> , <code>/auth/signup</code> no token is sent along with the request but if it is to a protected route it fetches the access token from our api route and passes it in the <code>Authorization</code> header.</p><h2 id="c7b2">Further reading:</h2><p id="fb63">This article was greatly inspired by:</p><div id="b5f3" class="link-block"> <a href="https://javascript.plainenglish.io/next-js-secure-authentication-using-http-only-cookie-graphql-or-rest-a4ef94cec9e8"> <div> <div> <h2>Next.js Secure Authentication Using http-only Cookie (GraphQL or REST)</h2> <div><h3>When it comes to user authentication we need to make sure our application is secured from any potential threats. To…</h3></div> <div><p>javascript.plainenglish.io</p></div> </div> <div> <div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/1*FBBZ5ksEs057sEfEkcl42g.png)"></div> </div> </div> </a> </div><p id="7edc">If you want to see how to do this with graphql. or you are working on older versions of Next without server actions, I suggest the article.</p><p id="948d">Thanks for reading and if you have any questions, drop them in the comments.</p><p id="50be">Happy building!🚀</p><h1 id="d403">Stackademic</h1><p id="3a1b"><i>Thank you for reading until the end. Before you go:</i></p><ul><li><i>Please consider <b>clapping</b> and <b>following</b> the writer! 👏</i></li><li><i>Follow us on <a href="https://twitter.com/stackademichq"><b>Twitter(X)</b></a>, <a href="https://www.linkedin.com/company/stackademic"><b>LinkedIn</b></a>, and <a href="https://www.youtube.com/c/stackademic"><b>YouTube</b></a><b>.</b></i></li><li><i>Visit <a href="http://stackademic.com/"><b>Stackademic.com</b></a> to find out more about how we are democratizing free programming education around the world.</i></li></ul></article></body>

Weekly Prompt: Big Band Versus Rap

Join us for battle between the Kings of Swing and the Slinging Kings.

Photo by Chase Fade on Unsplash

Welcome to the third weekly challenge for March, where our theme is March to your own Drummer, a musical challenge to tease our muse onto the dancefloor.

Big Band

A type of ensemble jazz, that dominated the 1940s when swing was all the rage has a special place in my heart, because this was the first song of our wedding dance.

Benny Goodman’s Sing Sing Sing kicked off one hell of a party. The DJ still uses the photo from our wedding to promote his business ten years later.

This scene from Swing Kids, which I must have watched when I was around seven, was probably where this seed first took hold.

My adult interpretation, 20 years later, was that if a husband and wife can move together like this, what can’t they handle?

Rap

One thing I know for sure is that writing to Rap, my personal favourite Power Rap (because that’s the playlist Google Music served me then) is great for cranking out Atomic Essays. Non-fiction for me spins out easily when listening to Rap.

This will be an interesting challenge to write fiction while listening to their rhythmic poetry. Now, I’m no Rap aficionado, but one thing that I do know, this scrawny white guy spits out lyrics way too good to call it quits.

For much less laughable lines, watch the 8 Mile Final Rap Battles.

But, for now…

You better lose yourself in the music, the moment You own it, you better never let it go

Headphones on, eyes closed, and go!

Challenge Requirements

Your story must:

  1. Tell us a fictional story inspired by your song choice.
  2. Be min 100 and max 1000 words long, excluding the title, subtitle, and any post-story bio/links. (We use Medium’s own word count feature.)
  3. Use “Rap” as one of your five tags. We recommend Fiction, Flash Fiction and maybe your genre too. But it’s your choice.
  4. Please link back to the prompt so others can find it easily.
  5. Oh, and don’t forget to share your song at the end!

Example Story:

First published story for this prompt goes here.

If you love what we do — say thanks with a coffee. ❤️

PS — Why all the personal connections to certain songs? I heard from a credible source, we should write what we know, what means something to us and spark a connection. The emotion shines through, and that’s what we’re trying to do, right? Emotional telepathy, mind to mind, through words.

Here’s how to write for Microcosm. We’d love to see your stories.

Writing Prompts
Fiction Writing
Writing Challenge
Writing Tips
Fiction
Recommended from ReadMedium