I'm trying to figure out how to correctly use msal to acquire token with the redirect method.
I have the following function:
function acquireTokenRedirect() {
const params = {
redirectUri: 'http://localhost:8080/admin/',
scopes: ['user.read']
};
console.log('Acquire token via redirect');
msal.acquireTokenRedirect(params);
}
And the callback:
msal.handleRedirectCallback((error, response) => {
console.log('Redirect call back is called');
});
When I call the method, this is what I get in Chrome console:
Acquire token via redirect
Navigated to http://localhost:8080/admin/
Redirect call back is called
GET http://localhost:8080/ 404 (Not Found)
Navigated to http://localhost:8080/
Why does it redirect to http://localhost:8080/ when I specifically tell it to redirect to http://localhost:8080/admin/?
MSAL is configured to use redirectURI: http://localhost:8080/admin/, and the same redirect is specified in the Azure portal for the project.
In comparison, msal.loginRedirect() redirects to the correct URI.
I suppose this is related to the solution in this issue :
To avoid the extra redirect, what I needed to do is set the
"navigateToLoginRequestUrl" param in Auth config to false. This solves
my problem.
Reference : msal in React SPA - use access token received from AcquireTokenRedirect
Let me know if that helps
Related
I need to redirect our users to a SSO form that is handle by another team. This form (is not a next.js app) is on the same domain as the next.js app.
I try to follow https://nextjs.org/docs/authentication#authenticating-server-rendered-pages but I can't figure out on how to get the current URL, so I can tell the SSO to redirect back once authentication is finish.
return {
redirect: {
destination: `/sso/form?redirect=${currentUrl}`,
permanent: false,
},
}
Any idea, on how to get the currentUrl?
The context contain a property called resolvedUrl corresponding to the current route.
const { resolvedUrl, req } = context;
const baseUrl = getBaseUrl(req);
const currentUrl = `${baseUrl}${resolvedUrl}`;
getBaseUrl is an helper function that return the base url of our current nextjs app.
The redirection you are doing on the getServerSideProps is done in the server so no dom info can be accessed on that level. You have tu pass the path info to the server in a cookie or something like that.
Anyway, if im not mistaken, you redirect to SSO when you try to load a page and the auth fails. This auth happens on getServerSideProps so you can hardcode the SSO redirection url because you call a different getServerSideProps everytime you go to a new page.
In Nuxt.js this is one way to implement authentication :
The client authenticates by sending an HTTP request with its credentials in the body to an API route of the Nuxt backend ;
The Nuxt backend responds with a JWT token that allows the client to access protected routes ;
Finally, when the authenticated user tries to access such a route, they make an HTTP request to the Nuxt backend with their JWT token inserted in the header ;
The backend validates the JWT token and responds with the requested page JSON data to the client.
What I don't understand is how to make the Nuxt backend aware that for some protected routes it has to check the JWT token of the client before providing the page JSON data. I mean, where exactly in Nuxt can I implement this kind of validation ?
Well i am confused a bit first you say API data the other sentece you say JSON page.. however. If you want to protect an PAGE then you create an middleware
middleware/auth.js
export default async function ({ store, $axios, redirect }) {
let valid = await $axios.$post('/api/checktoken')
if (!valid) {
redirect('/')
}
}
You need to create an API where you check the token. Usually you need to put the token in your header like Authentication: Bearer token... however i simply save my token inside an cookie. Because if you send an HTTP request to the server the cookies gets automatically sended with it so i dont need to do some extra work.
Next step is you go to some page and set your middleware auth.
page.vue
<script>
export default {
middleware: "auth"
}
</script>
However if you want to protect some backend routes you can do it like this. Create again an middleware
async authenticate(req, res, next) {
let token = await cookieService.getTokenFromCookie(req)
if (!token) return errorService.resError(res, 400, 'Authorization failed')
let tokenValid = await tokenService.verifyToken(token)
if (!tokenValid)
return errorService.resError(res, 400, 'Authorization failed')
let decodedData = tokenService.decode(token)
if (!decodedData)
return errorService.resError(res, 400, 'Authorization failed')
res.locals.userId = decodedData.userId
res.locals.role = decodedData.role
next()
}
In this case you basically need to read the token out of your cookie. (in case you dont use cookies you will need to read it out of your header so for this you should create an function that reads your token out of the header)
Check if token is even there.
Verify if token is valid.
Decode the token so you can access the data in it
Now you can also put the data to your res.locals. The advantage is that this data is scoped to this current request and you can access it in the next middleware / endpoint.
then you call next() to step to the next middleware / endpoint
function endpoint(req, res) {
let { userId, role } = res.locals
do something....
}
So the route looks something like this:
app.use("/some/api/point", authenticate, endpoint)
The good thing about is you can put authenticate in every API route you want to protect.
I am building a back-office app that requires users to sign in.
I have 2 external APIs:
API A : to manage user accounts and sessions
API B : to perform CRUD actions on another database (unrelated to users database)
The problem is that I don't want users to be able to perform calls to API B if their session is not valid. So I added some API endpoints in Next (under pages/api) that do the following actions:
verifying the validity of the session against API A
if session is valid: continue to step 3, if not: redirect to page /login
make the call to API B
Everything works fine if the session is valid but it fails if the session is not valid.
I have tried
res.redirect(307, '/login').end()
and
res.writeHead(307, { Location: '/login' }).end()
but it didn't work. It fails even by specifying the whole path (http://localhost:3000/login). What I don't understand is that I am successfully redirected to my /login page if I make the request directly from the browser (GET http://localhost:3000/api/data). It doesn't work when I make the request with Axios inside a React component.
Any idea how I can fix this?
As #juliomalves and #yqlim explained, I had to make the redirect manually based on the response of the API.
Faced same problem solve using below code:
Api
res.status(200).json({ success: "success" }) //add at last of the api to give response
page
import Router from 'next/router'
let res = await fetch('api', {
method: 'POST', // or 'PUT'
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
})
if (res.status == 200) {
Router.push('/location')
}
Answer is correct as #Jules Grenier sayes,but provided an example
You do not need .end(). Have you tried res.redirect(307, '/login')?
In Next.js v12 and v13, the following works for me.
// /api/example.js
const handler = async function (req, res) {
// custom logic
if (failed)
return res.redirect(307, '/login')
}
export default handler;
The API request must be initiated by a <form>.
redirect will not work with <fetch>
I am attempting to implement 0Auth user authorization for my Next.js app using MoneyButton API. I am able to trigger the authorization request with client.requestAuthorization('auth.user_identity:read','http://localhost:3000');
And it works smoothly redirecting me to MoneyButton permission consent and back to my app with the code and state params in URL -> ?code=6aa72eef702eb710cd22715d797cf7d27e06532a&state=38984b9d-3af0-48f1-8b5f-3fa47f4dfd9d
There is client.handleAuthorizationResponse(); method for handle the response. That method automatically gets the tokens from the query parameters and set the internal state of the client to use them. Also it saves the credentials in local storage, so the user stays logged in with Money Button if they close the browser.
But unfortunately i don't know how to use this method after being redirected back to my app. I am using it in Authuser function, but requestAuthorization triggers redirect to moneybutton, so rest of the function is not executed. How to use handleAuthorization after being redirected back to application?
https://docs.moneybutton.com/docs/api/auth/api-auth-jsclient.html - here are the MoneyButton docs
I am also considering to add MoneyButton as custom 0Auth provider in NextAuth.js to make integrations faster in the future.
Authuser.js
const { MoneyButtonClient } = require('#moneybutton/api-client')
export default function Authuser () {
const client = new MoneyButtonClient('MYAPP_OAUTH_IDENTIFIER_CODE');
client.requestAuthorization('auth.user_identity:read','http://localhost:3000');
client.handleAuthorizationResponse();
const refreshToken = client.getRefreshToken();
client.setRefreshToken(refreshToken)
}
You need to make sure that client.handleAuthorizationResponse(); is run client side (not server side render) after the moneybutton auth has redirected back:
if ((new URLSearchParams(window.location.search)).has('code')) {
await client.handleAuthorizationResponse()
const accessToken = await client.getValidAccessToken()
...
}
I have a backend API written in Ruby and a client App that uses Angular. I'd like to authenticate the user to authenticate the user via the Angular app.
As such I've created my App on Asana. I'm having a few issues though:
First issue: I'm using the Authorisation Endpoint of Authorisation Code Grant. After reading the docs, I realised that I have to use Implicit Grant instead, which is more suitable for a browser-based app, however when I change it to Implicit Grant, save it and reload the page, it changes back to Authorisation Code Grant.
Then on my Angular App I have the following code:
var client = Asana.Client.create({
clientId: 133,
clientSecret: 'mysecretcode',
redirectUri: 'http://localhost:7699/profile'
});
client.useOauth({
flowType: Asana.auth.PopFlow
});
client.authorize().then(function () {
console.log('Auth completed');
}).catch(function (err) {
console.log(err);
});
client.users.me().then(function (result) {
console.log(result);
});
The above almost works. I do get redirected to Asana for the authorisation part, once I click on "Allow", I'm redirected back to my app, and I do get a code as part of the url. The code is something like:
http://localhost:7699/profile#access_token=very_long_string
If I understood the docs correctly, I could use the above access_token to make my first request. When I tried using Asana's JS library to make a request like so:
client.users.me().then(function (result) {
console.log(result);
});
Please note the client object I'm referring to is the same I've created earlier for authorisation. The above returns a 401, Unauthorised code.
Then I tried the following:
var params = {
grant_type: 'refresh_token',
client_id: 876787,
client_secret: 'some_secret',
redirect_uri: 'http://localhost:7699/profile',
code: my_access_code
};
$http.post('https://app.asana.com/-/oauth_token', params).then(function (result) {
console.log(result);
});
Which also gets me a 401 unauthorised code.
What am I doing wrong here?
I recommend you start by copy-pasting one of the examples from the node-asana examples directory into your app, and seeing if that works.
If you want to keep using the popup flow, the thing I suspect you are missing is the call to Asana.auth.PopupFlow.runReceiver(); in popup_receiver.html. This should be on the page pointed to by your redirect_uri, and tells the page that created the popup the auth data it needs to make subsequent requests. Also note how the page that originates the authentication request (popup.html) includes actions that happen after authentication in the callback passed to then: this ensures that these actions happen only after the user completes authentication through the popup.