When calling refresh token, I get an undefined RefreshToken back.
SDK version number
#aws-sdk/client-cognito-identity-provider#3.72.0
Steps to reproduce
Get a refresh token and use it in an REFRESH_TOKEN_AUTH request:
const refreshToken = "REFRESH TOKEN GOES HERE";
const client = new AWS.CognitoIdentityProvider({ region: "eu-west-1" });
client.initiateAuth({
AuthFlow: AuthFlowType.REFRESH_TOKEN_AUTH,
ClientId: 'XYZ',
AuthParameters: {
REFRESH_TOKEN: refreshToken
}
}).then(w => {
console.log(w);
})
Result:
{ '$metadata': { httpStatusCode: 200, requestId: '<removed by OP>', extendedRequestId: undefined, cfId: undefined, attempts: 1, totalRetryDelay: 0 }, AuthenticationResult: { AccessToken: '<removed by OP>', ExpiresIn: 300, IdToken: '<removed by OP>', NewDeviceMetadata: undefined, RefreshToken: undefined, <!----------? ---------!> TokenType: 'Bearer' }, ChallengeName: undefined, ChallengeParameters: {}, Session: undefined }
Notice the RefreshToken is undefined.
I expected to get a new RefreshToken as well. Does anyone know why this isn't the case?
Related
I create a custom user registration because nextauth does not support registration. Everything works correctly but I do not know how after a successful registration of the user immediately log him in the credentials that he gave during registration.
As far as I can see, the signIn method from nextauth does not allow any credentials to be passed on to it. Redirects only to the login subpage.
I also did not find any endpoint that provides nextauth to which I can pass parameters so as to log in the user.
In fact, it is enough to call the authorize method that is in nextauth, unfortunately, there is no possibility to export it or there is no way to call it from the call to api level and it is a pity because with it I could log in the user.
User flow
User registers if the registration is successful, he is immediately logged in credentials that he provided during registration
My registration
async function handleRegister(
username: string,
email: string,
password: string
) {
const registerUser = await fetch(
`${process.env.API_URL}`,
{
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
body: JSON.stringify({
username,
email,
password,
}),
}
);
const registerResponse = await registerUser.json();
if (registerResponse.user) {
// TODO: Login with NextAuth
}
}
[...nextauth].ts
export default NextAuth({
providers: [
CredentialsProvider({
name: "Credentials",
credentials: {
identifier: {
label: "Email or Username",
type: "text",
placeholder: "jsmith",
},
password: { label: "Password", type: "password" },
},
async authorize(credentials, req) {
const res = await fetch(
`${process.env.NEXT_PUBLIC_API_URL}/api/auth/local`,
{
method: "POST",
body: JSON.stringify(credentials),
headers: { "Content-Type": "application/json" },
}
);
const user = await res.json();
if (res.ok && user) {
return user;
}
return null;
},
}),
],
session: {
strategy: "jwt",
},
jwt: {
maxAge: 60,
encode: async ({ secret, token }) => {
const encodedToken = jsonwebtoken.sign(token!, secret, {
algorithm: "HS256",
});
return encodedToken;
},
decode: async ({ secret, token }) => {
const decodedToken = jsonwebtoken.verify(token!, secret, {
algorithms: ["HS256"],
});
return decodedToken as JWT;
},
},
callbacks: {
jwt: async (token, user, account) => {
const isSignIn = user ? true : false;
if (isSignIn) {
token.jwt = user.jwt;
token.id = user.user.id;
token.name = user.user.username;
token.role = user.user.user_role;
token.email = user.user.email;
}
return Promise.resolve(token);
},
session: async ({ session, token }) => {
if (session.user) {
session.user.id = token.sub!;
}
return session;
},
},
secret: process.env.JWT_SECRET,
});
You need to login with credentials e.g
const response: SignInResponse | undefined = await signIn(
"credentials",
{
redirect: false,
email: "example#user.com",
password: "12345678",
}
);
I'm doing socials login with firebase (facebook and google is ok) but have problem with microsoft
I used expo-auth-session to get the response.params.code from Azure
if (type === 'facebook') {
requestConfig = Facebook.useAuthRequest({
clientId: DEFAULT_AUTH_CONFIG.facebookAppId,
});
} else if (type === 'microsoft') {
const microsoftConfig = {
clientId: DEFAULT_AUTH_CONFIG.msClientId,
scopes: ['openid', 'profile', 'email'],
redirectUri: makeRedirectUri({
scheme: DEFAULT_AUTH_CONFIG.msScheme,
}),
tenantId: DEFAULT_AUTH_CONFIG.msTenantId,
grantType: 'authorization_code',
};
const discovery = useAutoDiscovery(
`https://login.microsoftonline.com/${microsoftConfig.tenantId}/v2.0`,
);
requestConfig = useAuthRequest(microsoftConfig, discovery);
}
const [request, response, promptAsync] = requestConfig;
and then use exchangeCodeAsync to get the idToken + accessToken
const { accessToken, idToken } = await exchangeCodeAsync(
{
code,
clientId: DEFAULT_AUTH_CONFIG.msClientId,
redirectUri: makeRedirectUri({
scheme: 'https://cbot-dev.firebaseapp.com/__/auth/handler',
}),
scopes: ['openid', 'profile', 'email'],
extraParams: { code_verifier: request.codeVerifier },
},
{
tokenEndpoint: `https://login.microsoftonline.com/${DEFAULT_AUTH_CONFIG.msTenantId}/oauth2/v2.0/token`,
},
);
Next I use signInWithCredential as shown below but get wrong providerId or credential error If anyone has encountered this problem, please help me
const provider = new OAuthProvider('microsoft.com');
const credential = provider.credential({
idToken,
accessToken,
});
signInWithCredential(getAuth(), credential).catch((error) => {
console.log(error);
toast.error(formatError(error));
});
error:
Firebase: Invalid IdP response/credential: http://localhost?&id_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6ImpTMVhvMU9XRGpfNTJ2YndHTm...
I'm looking to pass the request context into a KOA middleware that is generated from a require (https://github.com/Shopify/koa-shopify-auth). I set some API keys that I need to pass into it from a previous middleware but have no access to them when I reach createShopifyAuth.
I've tried passing in the global server.context but it doesn't seem to be set from the previous middleware.
server.use(async (ctx, next) => {
await shopifyKeys;
if (url.parse(ctx.originalUrl, true).query.shop) {
const shops = url.parse(ctx.originalUrl, true).query.shop;
server.context.keys = [shopifyKeys[shops].key, shopifyKeys[shops].secret];
console.log(server.context.keys);
}
return next();
});
server.use(
createShopifyAuth({
apiKey: server.context.keys[0],
secret: server.context.keys[1],
scopes: [
'read_products',
'read_checkouts',
'read_orders',
'write_orders',
],
async afterAuth(ctx) {
const { shop, accessToken } = ctx.session;
ctx.cookies.set('shopOrigin', shop, {
httpOnly: false,
secure: true,
sameSite: 'none',
});
const registration = await registerWebhook({
address: `${HOST}/webhooks/orders/paid`,
topic: 'ORDERS_PAID',
accessToken,
shop,
apiVersion: ApiVersion.July20,
});
if (registration.success) {
console.log('Successfully registered webhook!');
} else {
console.log(
'Failed to register webhook',
registration.result.data.webhookSubscriptionCreate.userErrors,
);
}
ctx.redirect('/');
},
}),
);
Any help with figuring out how to get the context into the second server.use would be appreciated.
I am allegedly a newbie when it comes to KOA, but the only way I manage to make it was passing the data via cookies, individually. Here is an example:
server.use(
createShopifyAuth({
apiKey: SHOPIFY_API_KEY,
secret: SHOPIFY_API_SECRET_KEY,
scopes: [
"read_products",
"write_products",
"read_script_tags",
"write_script_tags",
"read_themes",
"write_themes",
],
accessMode: "offline",
afterAuth(ctx) {
const { shop, accessToken } = ctx.session;
ctx.cookies.set("shopOrigin", shop, {
httpOnly: false,
secure: true,
sameSite: "none",
});
ctx.cookies.set("accessToken", accessToken, {
httpOnly: false,
secure: true,
sameSite: "none",
});
ctx.redirect("/");
},
}),
);
Why my jwt token doesn't expire after 1 hour?
I've noticed that it doesn't expire when I forgot to logout my account in my admin panel that I created in vuejs with vuex.
here is my API that I created in ExpressJS using bcrypt and express-jwt for token.
router.post('/login', (req, res) => {
let sql = "SELECT * FROM AUTHENTICATION WHERE email = ?";
myDB.query(sql, [req.body.email, req.body.password], function (err, results) {
if (err) {
console.log(err);
} else {
if (!results) {
res.status(404).send('No user found.')
} else {
try {
let passwordMatched = bcrypt.compareSync(req.body.password, results[0].password);
if (passwordMatched) {
// Passwords match
let token = jwt.sign({ id: results.id }, config.secret, {
expiresIn: '1h'
});
res.status(200).send({ auth: true, token: token, user: results });
} else {
//Password doesn't match
return res.status(401).send({ auth: false, token: null });
}
} catch (error) {
res.send({ Success: false })
}
}
}
})
});
here's my login in vuex where I received the token from my backend.
import axios from 'axios';
const state = {
status: '',
token: localStorage.getItem('token') || '',
user: {}
};
const getters = {
isLoggedIn: state => !!state.token,
authStatus: state => state.status,
};
const mutations = {
auth_request(state) {
state.status = 'loading'
},
auth_success(state, token, user) {
state.status = 'success'
state.token = token
state.user = user
},
auth_error(state) {
state.status = 'error'
},
logout(state) {
state.status = ''
state.token = ''
},
};
const actions = {
login({ commit }, user) {
return new Promise((resolve, reject) => {
commit('auth_request')
axios({ url: 'http://localhost:9001/login/login', data: user, method: 'POST' })
.then(resp => {
const token = resp.data.token
const user = resp.data.user
localStorage.setItem('token', token)
// Add the following line:
axios.defaults.headers.common['Authorization'] = token
commit('auth_success', token, user)
resolve(resp)
})
.catch(err => {
commit('auth_error')
localStorage.removeItem('token')
reject(err)
})
})
}
};
EDIT: Added vuejs code for login
thanks for the help guys!
Your JWT token is just an encoded + signed JSON with relevant fields such as expiresIn, iat.
While it may contain the expiresIn field, it does not mean that the backend server will honour it.
Logic needs to be written in the backend server to parse the timestamp, do comparison with the current time to determine whether it has expired. If it is expired, the backend should return a response code of 401 Unauthorized to tell the frontend (your Vue client) that the token is no longer valid.
What you can do is to put the expiry-checking logic in a middleware to look into the request headers' Authorization field.
I am trying to retrieve the user from my JWT token which is being served from a Django-Rest API endpoint, /get-token/ and store the user in my Vuex Store.
I don't have an endpoint set up to return the logged in user, and while this could be a potential solution I see no reason to do that instead of retrieving the user from the JWT token.
I've tried retrieving the user directly from the JSON token via this.$store.commit('setAuthUser', response.data.user) and response.data.user.username
Login.Vue
axios.post(this.$store.state.endpoints.obtainJWT, payload)
.then((response) => {
this.$store.commit('updateToken', response.data.token)
this.$store.commit('setAuthUser', response.data.user) -------This line is not working
console.log(response.data)
})
store.js
export default new Vuex.Store({
state: {
authUser: {},
isAuthenticated: false,
jwt: localStorage.getItem('token'),
endpoints: {
obtainJWT: 'http://127.0.0.1:8000/get-token/',
refreshJWT: 'http://127.0.0.1:8000/refresh-token/',
baseUrl: 'http://127.0.0.1:8000/main/api/',
}
},
mutations: {
setAuthUser(state, {
authUser,
isAuthenticated
}) {
Vue.set(state, 'authUser', authUser)
Vue.set(state, 'isAuthenticated', isAuthenticated)
},
updateToken(state, newToken) {
localStorage.setItem('token', newToken);
state.jwt = newToken;
},
removeToken(state) {
localStorage.removeItem('token');
state.jwt = null;
}
}
});
Expected: Properly retrieved user and stored in Vuex with setAuthUser mutator
Actual: Error Cannot destructure property 'authUser' of 'undefined' or 'null'.