FCM - "messaging/registration-token-not-registered" - but the client is still using the token? - firebase-cloud-messaging

When sending a multicast message to FCM...
const message = {
notification: {
title: messageTitle,
body: messageBody,
},
tokens: tokenArray,
}
getMessaging().sendMulticast(message)
I'm receiving this error.
messaging/registration-token-not-registered - Requested entity was not
found
According to this post, I should then remove the token.
Here's what I'm confused about though. When I run getToken() on my client device, it's still showing this same token.
getToken(messaging, { vapidKey: "MY_VAPID_KEY"}).then(token => console.log(token))
Is there like a registration step that I'm missing? I don't understand why the client is using this as the current token but FCM thinks it's unregistered.

So my solution was I reset the browser cache and notification permissions. My browser then generated a new token which is working.
Kind of strange though is on the first call of getToken() after clearing and refreshing, it sent a request to delete the token after failing a check with isTokenValid(), and then the delete itself failed so my token remained registered and is now working. No idea what's going on there.

Related

vue.js jwt token refresh with axios interceptors

im trying to refresh users jwt token in vue.js.So my solution would be when the user send a request with expired token got rejected with status code 401 and then in axios intereceptors I try to refresh the token with sending a token refresh request to my backend. The problem is when the token refresh happens it didn't repeat the original request
axios.interceptors.response.use(function (response) {
return response
}, async function (error) {
if(error.response.status===401){
let newtokens= await axios.post('RefreshToken',{
oldtoken:store.state.user.token,
refreshtoken:store.state.user.refreshtoken
})
let user=store.state.user
console.log(user)
user.token=newtokens.data.token
user.refreshtoken=newtokens.data.refreshtoken
axios.defaults.headers.common['Authorization']='Bearer '+ user.token
console.log(newtokens)
store.dispatch("user",user)
console.log(store.state.user)
return axios(error.config)
}
return Promise.reject(error)
})
I tried to console log what happens in the axios interceptors and it looks like it has been successfully send the request to the backend and refresh the user token. The only problem is it didn't repeat the original request
if your axios version is between (1.1.0) to (1.1.3) then such issue occured but on downgrade to version (0.27.2) works well.
Github issue:https://github.com/axios/axios/issues/5143
And it seems still issue hasn't been solved for higher version

invalid_grant exchanging authorization code for access and refresh tokens

My application is using OAuth to access the Youtube Data API. My OAuth callback is written in node and uses the OAuth2Client class from the "googleapis" npm package to exchange the authorization code for the access and refresh tokens.
Everything was working fine up to last week until suddenly I started getting the "invalid_grant" response during the authorization code exchange. I have tried everything to resolve this and am running out of ideas. My callback executes as a cloud function so I don't think that it would be out of sync with NTP.
My OAuth consent screen is in "Testing" mode and my email address is included in the test users. The odd thing is that even though the authorization code exchange fails, my Google account's "Third-party apps with account access" section lists my application as if the handshake succeeded.
Is there a limit to how many refresh tokens can be minted for my application? I am testing my implementation of incremental authorization so I have been going through the OAuth flow often.
Edit
I've included my code for generating the auth URL and exchanging the authorization code below. The invalid_grant occurs during the call to "oauth2.getToken"
async startFlow(scopes: string[], state: string): Promise<AuthFlow> {
const codes = await oauth2.generateCodeVerifierAsync();
const href = oauth2.generateAuthUrl({
scope: scopes,
state,
access_type: 'offline',
include_granted_scopes: true,
prompt: 'consent',
code_challenge_method: CodeChallengeMethod.S256,
code_challenge: codes.codeChallenge
});
return { href, code_verifier: codes.codeVerifier };
}
async finishFlow(code: string, verifier: string): Promise<Tokens> {
const tokens = await oauth2.getToken({ code, codeVerifier: verifier })
return {
refresh_token: tokens.tokens.refresh_token!,
access_token: tokens.tokens.access_token!,
expires_in: tokens.tokens.expiry_date!,
token_type: 'Bearer',
scopes: tokens.tokens.scope!.split(' ')
};
}
"oauth2" is an instance of OAuth2Client from "google-auth-library". I initialize it here:
export const oauth2 = new google.auth.OAuth2({
clientId: YT_CLIENT_ID,
clientSecret: YT_CLIENT_SECRET,
redirectUri: `${APP_URI}/oauth`
});
Looking at the logs, the only out of the ordinary thing I notice is that the application/x-www-form-urlencoded body looks slightly different than the example https://developers.google.com/identity/protocols/oauth2/web-server#exchange-authorization-code
The POST request to "https://oauth2.googleapis.com/token" ends up looking like this:
code=4%2F0AX4XfWiKHVnsavUH7en0TywjPJVRyJ9aGN-JR8CAAcAG7dT-THxyWQNcxd769nzaHLUb8Q&client_id=XXXXXXXXXX-XXXXXXXXXXXXXXX.apps.googleusercontent.com&client_secret=XXXXXX-XXXXXXXXXXXXXXX-XX_XXX&redirect_uri=https%3A%2F%2Fapp.example.com%2Foauth&grant_type=authorization_code&code_verifier=KjOBmr4D9ISLPSE4claEBWr3UN-bKdPHZa8BBcQvcmajfr9RhWrgt7G429PLEpsP7oGzFGnBICu3HgWaHPsLhMkGBuQ2GmHHiB4OpY2F0rJ06wkpCjV2cCTDdpfRY~Ej
Notice that the "/" characters are not percent-encoded in the official example, but they are in my requests. Could this actually be the issue? I don't see how the official google auth library would have an issue this large.
The most common cause for the invalid_grant error is your refresh token expiring.
If you check oauth2#expiration you will see the following
A Google Cloud Platform project with an OAuth consent screen configured for an external user type and a publishing status of "Testing" is issued a refresh token expiring in 7 days.
Once you set your project to production your refresh tokens will stop expiring.
Is there a limit to how many refresh tokens can be minted for my application?
No but you have a limit of 100 test users.

Strapi doesn't authorize JWT

Good morning,
I've encountered a weird issue with my strapi-project.
I have a standard user model which I query for info on the user's profile page via the /users/me endpoint. This was all working fine last week but as I tried logging in this morning, the authorization appeared to not work anymore. I log my user in via this code:
....
async submitForm() {
axios.post('http://localhost:1337/auth/local', {
'identifier': this.email,
'password': this.password
})
.then((response) => {
const { jwt, user } = response.data;
window.localStorage.setItem('jwt', jwt);
window.localStorage.setItem('userData', JSON.stringify(user));
router.push('/dashboard');
})
.catch((e) => {
this.$store.commit('LOGIN_ERROR', e)
});
},
...
Which then redirects to my dashboard which queries the /users/me endpoint like so:
let token = localStorage.jwt;
axios.get(`http://localhost:1337/users/me`, {
headers: {
Authorization: `Bearer ${token}`
}
})
.then((response) => {
console.log(response.data);
})
A few days ago this was working fine, also the token variable used in the post contais the token returned from the backend after logging in. Now strapi gives me an error in the console:
[2021-10-16T07:16:52.568Z] debug GET /users/me (5 ms) 500
[2021-10-16T07:17:03.231Z] debug POST /auth/local (76 ms) 200
[2021-10-16T07:17:24.915Z] error TypeError: Cannot read property 'type' of null
at module.exports (/home/user/WebstormProjects/strapi-project/node_modules/strapi-plugin-users-permissions/config/policies/permissions.js:35:14)
at async /home/user/WebstormProjects/strapi-project/node_modules/strapi-utils/lib/policy.js:68:5
at async serve (/home/user/WebstormProjects/strapi-project/node_modules/koa-static/index.js:59:5)
at async /home/user/WebstormProjects/strapi-project/node_modules/strapi/lib/middlewares/parser/index.js:48:23
at async /home/user/WebstormProjects/strapi-project/node_modules/strapi/lib/middlewares/xss/index.js:26:9
My first guess was that maybe something with axios was wrong e.g. that the token wasn't sent correctly in the request so I tried the same thing with webstorm's http client:
POST http://localhost:1337/auth/local
Content-Type: application/json
{
"identifier": "test#test.com",
"password": "..."
}
Which returns the user and token:
"jwt": "<TOKEN>",
If I try using this token to authenticate the user, however a get a 401
GET http://localhost:1337/users/me
Authorization: "Bearer <token>"
Accept: application/json
returns
{
"statusCode": 401,
"error": "Unauthorized",
"message": "Invalid token."
}
So I tried figuring out what was going on there and after an hour I noticed that when looking at the user in the backend the user didn't have the authenticated role assigned. When I changed this manually in the backend, the request authorization works again.
So can anyone maybe tell me what is going on here? Because from my understanding, when POSTing valid credentials to /auth/local the user's role should change to Authenticated, which was working some days back.
Is there something I'm missing?
Any help would be greatly appreciated,
greetings, derelektrischemoench
Okay, so let me reply to your first part:
"Because from my understanding, when POSTing valid credentials to /auth/local the user's role should change to Authenticated"
Answer is, not really. When you send valid credentials to the auth/local, Strapi just checks the database for matching username/email and password. If a user is found, then it fetches the role assigned that user and puts all the data in ctx.state.user.role. So you could have many other roles, like Viewer, Commenter etc with each having different set of access limits.
The different roles can be created here:
http://localhost:1337/admin/settings/users-permissions/roles
So depending on the roles assigned, Strapi will just fetch and store the values in ctx.state.user.role on each request via the strapi-plugin-users-permissions plugin for your convenience, so that you can easily check which user it is and which role it has in any controller or service file using the ctx from the request to provide any additional functionality.
You can check how it does it in the following file:
node_modules/strapi-plugin-users-permissions/config/policies/permissions.js
Now coming to what could have caused it:
Well it could have been you yourself. Possibly while saving the user or viewing user details you could have removed the role from the user and saved the record.
The other possibility could be a database switch.
It can also be a Strapi version upgrade that caused, but it's highly unlikely.
You could have a update query in the your code that updates the user model, where you might have missed the role parameter. So check your code once.
Nevertheless, it can simply be solved by re-assigning the user roles via the users module.

Nuxt SSR - i can't check if a user is authenticated

I'm trying to work on a Nuxt SSR frontend that uses a Django backend with Session Authentication.
I would like to have some SSR pages as well as client rendered pages in my frontend, so i'm using Universal mode.
The problem is that i did not find a working approach to check if a user is authenticated before loading a page, so i can't restrict pages to anonymous users. In order to check if a user is authenticated, Django will check if the request's headers contain a cookie, and according to that return if the user is authenticated or not.
Here is what i tried:
1) Middleware
export default async function ({context, redirect}) {
axios.defaults.withCredentials = true;
return axios({
method: 'get',
url: 'http://127.0.0.1:8000/checkAuth',
withCredentials: true,
}).then(function (response) {
//Redirect if user is authenticated
}).catch(function (error) {
console.log(error)
});
}
Here i'm sending a request to my backend to check if the user is authenticated. The problem is that the middleware is executed from server side, which means there will never be any cookie in the request, even if the user is authenticated. This means that every time i refresh the page, according to the middleware the user is always anonymous, even when the user is authenticated.
2) Plugin
export default function (context, inject) {
if (process.client){
console.log('client')
return axios({
method: 'get',
url: 'http://127.0.0.1:8000/checkAuth',
withCredentials: true,
}).then(function (response) {
//IF AUTHENTICATED, REDIRECT
context.redirect('/')
}).catch(function (error) {
console.log(error)
});
} else {
console.log('server')
}
}
Here i'm trying the same but with a plugin, and i'm "forcing" the plugin to check if the user is authenticated on the backend only when the plugin executes from client side. This works, cookies are sent in the headers and Django receives the cookie, but the problem with this solution is that Nuxt doesn't allow redirecting to other pages from a plugin (https://github.com/nuxt/nuxt.js/issues/4491).
3) Using beforeMount() in Vue
I tried to do that using beforeMount() from my Vue pages, but the problem is that since it will execute AFTER idration, the page will be loaded and after 1/2 seconds the redirect happens, which is kind of ugly.
Is it possible that there isn't a way to do this? Any kind of advice is appreciated
EDIT: the problem is not that i don't know how to code this, the problem is that when Nuxt sends a request to my backend from the server side middleware, the request will not contain any cookie, and because of this my Django backend cannot check the session cookie, which means that the backend cannot check whether or not the user is authenticated. The same code works when the middleware is executed from client side (if i navigate directly to the page instead of refreshing), because the request will contain the cookies.
I'm trying to understand if this is normal or not, but this could be an issue with Nuxt.
I know this a year old question and it was probably about nuxt 2, now nuxt 3 is out and running and I found my self with the same problem and here is how I solved it, just in case someone stumble here just like I did.
With Nuxt 3 server side you can use useFetch with the options headers: useRequestHeaders(['cookie'])
const { data, error, pending, refresh } = await useFetch(api.auth,
{
credentials: "include",
headers: useRequestHeaders(['cookie'])
}
);
There are a few issues you need to be aware of:
_ The cache, if you perform the same request with the same parameters it will return the same cached response (it won't even call the end point API). Try to use the key option with different values or the returned refresh method and check the doc "Data fetching" for more info.
_ The cookies, any cookie generate server side won't be shared with the client side, this means if the API generate a new token or session cookie on server side the browser won't receive those cookies and may generate new ones, this may get you in some 400 - bad request if you use session with CSRF, check this issue for more info.
I do have a working middleware with this
export default ({ redirect, store }) => {
if (store?.$auth?.$state?.loggedIn) {
redirect('https://secure.url')
} else {
redirect('https://login.please')
}
})

jwksError: Not Found thrown by jwks-rsa module during GET request with auth bearer token to protected api

An error - “jwksError: Not Found” is thrown when I make a get request with the correct bearer token in the request header to my protected API. I’ve followed the start up guide to create the jwtCheck helper function that I pass to all my routes to protect them. I need help clarifying what this error actually means thanks!
Here I define the helper function jwtCheck which will be used to secure all routes.
var jwtCheck = jwt({
secret: jwksClient.expressJwtSecret({
cache: true,
rateLimit: true,
jwksRequestsPerMinute: 5,
jwksUri: https://${auth0Domain}/.well-known/jwks.json,
}),
algorithms: ['RS256'],
issuer: https://${auth0Domain}/,
audience: auth0ApiIdentifier,
});
Then I protect my api using jwtCheck defined above like so. After which the api will throw an Unauthorized Error if one tries to send http requests to it without a header in the request with the auth bearer token.
const app = express();
...
app.use(jwtCheck);
...
I get new Bearer tokens by sending a POST request to auth0apiIdentifier/oauth/token and putting the following in the req body:
{
"client_id":id,
"client_secret":secret,
"audience":auth0apiIdentifier,
"grant_type":"client_credentials"
}
After sending the get request via postman with the appropriate bearer token in place, rwks-rsa module throws the subsequent error:
JwksError: Not found.
at ../server/node_modules/jwks-rsa/lib/JwksClient.js:119:23
at ../server/node_modules/jwks-rsa/lib/wrappers/request.js:36:12
at processTicksAndRejections (internal/process/task_queues.js:93:5)
Img 1 - POST request to get new auth Bearer token from Auth0
Img 2 - GET request sent with postman and corresponding error thrown by jwks-rsa module.
I've fixed it! The error was way too ambiguous but after desperation set in, I checked my configs again and I found that I included a "/" at the end of my auth0apiIdentifier, this allowed a "//" in the jwksUri which caused the issue. Solving this typo was my fix.
Check your code guys! Peace!