Feedly API with NuxtJS Axios - vue.js

I am trying to access the Feedly API via my nuxtjs site. To do so, I am using the nuxt-axios module.
To get started, I take note of the Feedly API instructions:
We offer a standard OAuth 2.0 authentication module which provide the application an OAuth access token. Most endpoints expect an Authorization header.
$ curl -H 'Authorization: OAuth [your developer access token]' https://cloud.feedly.com/v3/profile
I now attempt to integrate this into nuxtjs-axios.
First, I set up my nuxt-config.js file:
export default {
...
plugins: [{ src: `~/plugins/axios.js` }],
modules: [
'#nuxtjs/axios',
],
axios: {
credentials: true
},
env: {
FEEDLY_ACCESS_TOKEN:
[MY_FEEDLY_DEV_ACCESS_TOKEN]
},
...
}
I then create a axios.js plugin in the plugins folder (which is imported into the nuxt-config.js file that I noted above):
export default function({ $axios }) {
$axios.setHeader('Authorization', `OAuth ${process.env.FEEDLY_ACCESS_TOKEN}`)
}
The problem is that I have no idea what I'm supposed to put in the axios.js plugin file --- or even if that is the right way to do this. What I did is really just a stab in the dark.
So my question is, how can I implement the Feedly API into nuxtjs using the nuxtjs-axios module?
Thanks.

Use interceptor:
// Add a request interceptor
axios.interceptors.request.use(function (config) {
// Do something before request is sent
return config;
}, function (error) {
// Do something with request error
return Promise.reject(error);
});
// Add a response interceptor
axios.interceptors.response.use(function (response) {
// Any status code that lie within the range of 2xx cause this function to trigger
// Do something with response data
return response;
}, function (error) {
// Any status codes that falls outside the range of 2xx cause this function to trigger
// Do something with response error
return Promise.reject(error);
});
https://github.com/axios/axios/blob/master/README.md#interceptors

What I've understood of the nuxt-axios documentation is that the plugin.axios file is used for adding "default" behavior (axios helpers: https://axios.nuxtjs.org/helpers/)
I think that you've got the plugin right (if the token is the only thing you need to add to your header).
With the nuxt-axios enabled you can now use the this.$axios.get/post.
Have you tried to run a component with:
this.$axios.get('**feedly_url_api_url_here**').then(response)....

Related

Protect api routes with middleware in nextJS?

I'm new to next.js and I wanted to know if I could protect a whole API route via middleware. So for example if i wanted to protect /api/users Could I create /api/users/_middleware.ts and handle authentication in the middleware and not have to worry about authentication in the actual api endpoints? If so, how would I go about doing that? The library i'm using right now is #auth0\nextjs-auth0 so I guess it would look something like this? (Also please forgive me if I code this wrong, I am doing this in the stackoverflow editor)
export default authMiddleware(req,res)=>{
const {user,error,isLoading} = whateverTheNameOfTheAuth0HookIs()
if(user)
{
// Allow the request to the api route
}
else
{
// Deny the request with HTTP 401
}
}
Do I have the general idea correct?
next-auth v4 introduced middleware for this purpose. The basic use case is pretty simple.
You can add a middleware.js file with the following:
export { default } from "next-auth/middleware"
export const config = { matcher: ["/dashboard"] }
Other use cases can be found in the documentation
You can use middleware for that, something similar to this example from the documentation.
For a sub-directory inside pages, you can create a _middleware.ts file. It will run for all pages in this directory. It looks something like this:
import { NextRequest, NextResponse } from 'next/server'
export function middleware(req: NextRequest) {
const basicAuth = req.headers.get('authorization')
if (basicAuth) {
// do whatever checks you need here
const hasAccess = ...
if (hasAccess) {
// will render the specified page
return NextResponse.next()
}
}
// will not allow access
return new Response('No access', {
status: 401,
headers: {
'WWW-Authenticate': 'Basic realm="Secure Area"',
},
})
}
You can find more info in the documentation.

Strapi v4 Extending Server API for Plugins does not work

I am trying to follow the Strapi v4.0.0 guide on https://docs.strapi.io/developer-docs/latest/developer-resources/plugin-api-reference/server.html#entry-file for extending the users-permission plugin to add a custom route/controller, but so far have been unsuccessful. I add the custom files as stated in the docs, but there is no change in the UI.
I managed to get this to work for normal API highlighted in yellow, but was unable to do so for the users-permission plugin
In the previous version 3.6.8 this functionality was allowed through the extensions folder.
Am I missing something from the new guide, I even tried copying the files from node_modules > #strapi > plugin-users-permission and adding a new route and method to the exiting controller file but it still does not reflect the change in the section where we assign different route permission to roles. The user-permission plugin still shows the original routes, with no change.
Thanks,
I ran into this thread while researching pretty much the same issue, and I wanted to share my solution.
First of all, I found this portion of the documentation more useful than the one you referenced: https://docs.strapi.io/developer-docs/latest/development/plugins-extension.html
My goal was the write a new route to validate JWT tokens based on the comment made here: https://github.com/strapi/strapi/issues/3601#issuecomment-510810027 but updated for Strapi v4.
The solution turned out to be simple:
Create a new folder structure: ./src/extensions/user-permissions if it does not exist.
Create a new file ./src/extensions/user-permissions/strapi-server.js if it does not exist.
Add the following to the file:
module.exports = (plugin) => {
plugin.controllers.<controller>['<new method>'] = async (ctx) => {
// custom logic here
}
plugin.routes['content-api'].routes.push({
method: '<method>',
path: '/your/path',
handler: '<controller>.<new method>',
config: {
policies: [],
prefix: '',
},
});
return plugin;
};
If you're unsure what controllers are available, you can always check the API documentation or console.log(plugin) or console.log(plugin.controllers).
After the admin server restarts, you should see your new route under the user-permissions section as you would expect, and you can assign rights to it as you see fit.
My full strapi-server.js file including the logic to validate JWT:
module.exports = (plugin) => {
plugin.controllers.auth['tokenDecrypt'] = async (ctx) => {
// get token from the POST request
const {token} = ctx.request.body;
// check token requirement
if (!token) {
return ctx.badRequest('`token` param is missing')
}
try {
// decrypt the jwt
const obj = await strapi.plugin('users-permissions').service('jwt').verify(token);
// send the decrypted object
return obj;
} catch (err) {
// if the token is not a valid token it will throw and error
return ctx.badRequest(err.toString());
}
}
plugin.routes['content-api'].routes.push({
method: 'POST',
path: '/token/validation',
handler: 'auth.tokenDecrypt',
config: {
policies: [],
prefix: '',
},
});
return plugin;
};
When exporting routes you need to export the type, either content-api or admin. Look at the Strapi email plugin in node_modules for example, change the folder and file structure in your routes folder to match that and then you will be able to set permissions in the admin panel.
If your Strapi server is using Typescript, make sure that you name your extension files accordingly. So instead of strapi-server.js, you would need to name your file strapi-server.ts.

How to use Nuxt $auth inside an axios plugin (How to add Token to all axios requests)

Im looking to use $auth inside my Nuxt project, specially inside an axios plugin.
Here is my code:
plugins/api.js
export default function ({ $axios }, inject) {
const api = $axios.create({
headers: {
common: {
Accept: 'text/plain, */*',
},
},
})
// Set baseURL to something different
api.setBaseURL('http://localhost:4100/')
// Inject to context as $api
inject('api', api)
}
Now the problem comes when I try to use $auth from #nuxtjs/auth-next package.
As stated in the docs:
This module globally injects $auth instance, meaning that you can
access it anywhere using this.$auth. For plugins, asyncData, fetch,
nuxtServerInit and Middleware, you can access it from context.$auth.
I tried the following:
This results in $auth being undefined
export default function ({ $axios, $auth }, inject) {
This one was near
export default function ({ $axios, app }, inject) {
console.log(app) //This one logs $auth in the object logged
console.log(app.$auth) // I don't understand why but this one returns undefined
My main goal here is to make use of this.$auth.strategy.token.get()and pass it (if the token exists of course) to the headers of every request made using this.$api
I have been looking for similar questions and answers but none has helped me to solve this, I could just add the token every time I write this.$api but that would increase the code unnecessarily.
Thanks in advance to all the people for your time and help.
EDIT:
Okay, now I made a test. and the next code is actually logging the $auth object correctly, it seems some time is needed to make it work but now Im afraid that using setTimeout could cause an error because I can't know exactly how much time is needed for $auth to be available.
export default function ({ $axios, app }, inject) {
setTimeout(() => {
console.log('After timeout', app.$auth)
}, 50)
EDIT 2:
So now I have made more tests, and using 0 milliseconds instead of 50 works too, so I will use setTimeout with 0 milliseconds for now, I hope anyone find a better solution or explain why $auth is not available before using setTimeout so I can decide what to do with my code.
EDIT 3:
After trying to wrap all my previous code inside setTimeout I noticed that the code fails, so that isn't a solution.
I have found a solution so I will post it so that every person that could have the same problem in the future can solve it.
It turns out that I could easily solve it using interceptors.
export default function ({ $axios, app }, inject) {
// At this point app.$auth is undefined. (Unless you use setTimeout but that is not a solution)
//Create axios instance
const api = $axios.create({
headers: {
common: {
Accept: 'application/json', //accept json
},
},
})
// Here is the magic, onRequest is an interceptor, so every request made will go trough this, and then we try to access app.$auth inside it, it is defined
api.onRequest((config) => {
// Here we check if user is logged in
if (app.$auth.loggedIn) {
// If the user is logged in we can now get the token, we get something like `Bearer yourTokenJ9F0JFODJ` but we only need the string without the word **Bearer**, So we split the string using the space as a separator and we access the second position of the array **[1]**
const token = app.$auth.strategy.token.get().split(' ')[1]
api.setToken(token, 'Bearer') // Here we specify the token and now it works!!
}
})
// Set baseURL to something different
api.setBaseURL('http://localhost:4100/')
// Inject to context as $api
inject('api', api)
}
Also Nuxt Auth itself has provided a solution for this issue:
https://auth.nuxtjs.org/recipes/extend/

Next.js & Ant Design Dragger: File upload fails on deployed instance

I'm trying to build a file upload with Next.js and Ant Design using React.
On localhost, everything works fine. When I deployed the instance and try to upload a file, I get the following error:
Request URL: https://my-app.my-team.now.sh/url/for/test/
Request Method: POST
Status Code: 405
Remote Address: 34.65.228.161:443
Referrer Policy: no-referrer-when-downgrade
The UI that I use looks like the following:
<Dragger {...fileUploadProps}>{renderImageUploadText()}</Dragger>
where fileUploadProps are:
const fileUploadProps = {
name: 'file',
multiple: false,
showUploadList: false,
accept: 'image/png,image/gif,image/jpeg',
onChange(info) {
const { status } = info.file;
if (status === 'done') {
if (info.file.size > 2000000) {
setUploadSizeError('File size is too large');
} else {
handleFieldValue(API_FORM_FIELDS.PICTURE, info);
}
} else if (status === 'error') {
setUploadSizeError(`${info.file.name} file upload failed.`);
}
},
};
I assume, it has to do with the server side rendering of Next.js? On the other hand, it might not, because by the time I navigated to url/for/test it should render on the client.
How do you implemented file uploads with Ant Design and Next.js?
Got this to work by passing the prop action="https://www.mocky.io/v2/5cc8019d300000980a055e76" to the <Upload/> component.
The ANTD Upload component must make a POST request to upload the file. It either makes that POST request to the current url, which results in the 405, or to the url specified by the action prop. https://www.mocky.io/v2/5cc8019d300000980a055e76 works as this url.
Inspired by Trey's answer (and because I didn't want to send data anywhere outside my domain) I made a no-op api route that simply returns a success, and then pointed Ant Design <Upload>'s action to /api/noop
/* pages/api/noop.tsx */
import { NextApiRequest, NextApiResponse } from 'next'
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
res.status(200).end('noop')
}
/* Wherever I'm using <Upload /> */
<Upload
...otherProps
action={'/api/noop'}
>
Note: this is specific to Next.js, which makes it easy to create API routes.
This works for me.
By default, the ANTD upload component makes a POST request to upload the file. So, to avoid this, add a customRequest props on Upload as below.
customRequest={({ onSuccess }) => setTimeout(() => { onSuccess("ok", null); }, 0) }

hapi single page application using inert plugin doesn't serve up api route

I am trying to build a single page application using hapi and inert.
my example code is here: https://github.com/7seven7lst/hapi-inert-test
and the base of the project is built from the answer here nodejs hapi single page
Basically I would like to both server static file and api json data to front end. I know how to do this in express, but haven't figure out how with hapi. the delimma is : if I use hapi only, it doesn't serve up static file, and if i use hapi+inert, it wont' serve up api route.
solutions????
The documentation says that the route handler chooses the route from most specific to least specific. So you can pre-fix your api routes with something like /api/v1/ and then everything else that doesn't begin with /api/v1/ will get routed to static files dished up by inert.
Hapi.js Routing Documentation:
When determining what handler to use for a particular request, hapi searches paths in order from most specific to least specific. That means if you have two routes, one with the path /filename.jpg and a second route /filename.{ext} a request to /filename.jpg will match the first route, and not the second. This also means that a route with the path /{files*} will be the last route tested, and will only match if all other routes fail.
'use strict'
const Hapi= require('Hapi')
// Config
var config= {
connection: {port: 3000, host: 'localhost'}
}
const server= new Hapi.Server()
server.connection(config.connection)
const plugins= [
// https://github.com/hapijs/inert
{ register: require('inert'), options: {} },
]
function setupRoutes() {
// Sample API Route
server.route({
method: 'GET',
path: '/api/v1/Person/{name}',
handler: function (req, reply) {
reply('Hello, '+ encodeURIComponent(req.params.name)+ '!')
}
})
// Web Server Route
server.route({
method: 'GET',
path: '/{files*}',
// https://github.com/hapijs/inert#the-directory-handler
handler: {directory: {path: '../html_root', listing: false, index: true } }
})
}
server.register(plugins, (err)=> {
if (err) {throw err}
// Initialize all routes
setupRoutes()
// Start the Server
server.start((err)=> {
if (err) {throw err}
server.log('info', `Server running at: ${server.info.uri}`)
})
})