I'm using react in the front end and nodeJS in the backend.
I'm trying to have a google auth2 login flow from the front end.
Where can I get the token from a google auth2 login?
I see it in the response under Zi.access_token but it doesn't seem to me to be the right way to get it.
In order to access properties such as basic_profile, access_token, the Auth2 library provides a range of getter-functions that will allow you access the data in a predictable way.
For access_token, you should call the function getAuthResponse() on the GoogleUser object returned from a successful login, this GoogleUser object will contain a key clearly labeled access_token
For basic_profile, GoogleUser.getBasicProfile() is provided
I see it in the response under Zi.access_token but it doesn't seem to me to be the right way to get it.
You are right, and this is something perhaps the docs can mention.
Related
In our application, we authenticate users using AAD, but we authorize users using our own User and Role tables in our local SQL database.
With the old ADAL library, we were able to return users to our callback url, then from there we would grab the JWT token from the ADAL service, and send that token to our server. The server would then validate the token, decode it and grab the email address. We then used our SQL tables to return another JWT that contained the user's identity and all of their roles.
With MSAL, this still works if you use InteractionType.Popup. The response Observable from the loginPopup() method carries the AuthentiationResult, which has an idToken property and an accessToken property. You can easily grab the one you need and you're off to the races.
However, with InteractionType.Redirect we don't get the AuthenticationResult.
I have injected the msalService instance into the our callbackURL's component (called AuthCallbackComponent). I looked everywhere within the msalService for the tokens, but couldn't find them. I even looked in sessionStorage, where I've configured MSAL to cache the token. They are actually in there (under a couple of really funky keys), but not until later. Whether I use ngOnInit, ngAfterViewInit or ngAftercontentInit, the tokens are not there yet. It does work if I set a timeout of 1-2 seconds, but...no. You can never really rely on timeout delays being long enough for all of your users all the time.
We desire to use the Redirect workflow rather than the popup workflow, so it really would be ideal if we can just get the idToken from the MSAL instance.
I found this post here: Retrieve token using msal, which offers some possible solutions, but the suggestions aren't helpful. It talks about a custom MSAL Interceptor, but that seems wrong. That's typically the HTTP interceptor that adds your token to the headers of your service calls. It also says you can subscribe to the callback and "do something with the returned token", but assuming they mean the callback of the msalService.loginRedirect() method, well that is just wrong. It doesn't return anything at all.
Remember, that in the old ADAL library, this worked. Also it still works with InteractionType.Popup (which we can't use). I expect those tokens must be in the MSAL instance somewhere, or else there's a method we can override, a callback we can provide, etc.
Thanks for reading this longer post.
Buried deep within the 10K pages of Microsoft documntation on MSAL, I found this event reference:
https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-angular/docs/v2-docs/events.md#the-inprogress-observable
So I used their example code to come up with my solution, which was to inject the msalBroadcastService into my AuthCallbackComponent. There I subscribe to its msalSubject$, and when a LOGIN_SUCCESS event happens, I can get the accessToken and idToken from the event's payload. Here is some code:
ngOnInit(): void {
this.msalBroadcastService.msalSubject$.pipe(filter((msg: EventMessage) => msg.eventType === EventType.LOGIN_SUCCESS)).subscribe(msg => {
const idToken = (msg.payload as any).idToken;
// now I can call my service method, passing in the idToken
}
If a user logs in with user and password, he gets an new api key,
so react can access the Rest Api with his user account. How do you save this api key? And what happend if the user clicks 'refresh page'?
Of course I can initalize the Rest App every time with
<script>
window.REP_LOG_API_KEY = '19e8317a38b24af82da056f6ed36e831ea6b8f9bfcad996aaa56ec773f9f2e1d';
</script>
<script src="build/reactapp.js"></script>
but dont look very secure (but I like the idea of changing this key
every page request, if you have no single page application and react
is only used here and there).
To store the Api Key in a cookie would be also possible (secure but not
httponly, normally I only use safe cookies). Is this the only way?
I'm still not quite sure how to use react with a rest api
with individual api keys. Thany you.
The API key you are talking about is probably cookies/authentication token. If it is cookies, you need to enable httpOnly to prevent attacks. For authentication token, the most common way to store is in localStorage or sessionStorage. However, it is insecure, even with HTTPS and short expiry dates (and you do HAVE to use them). Putting it in Redux store is the same as putting it in a global js object where everyone can see.
What will protect your app is to check standard headers to verify the request is same origin (source and target origins check) and CSRF token. Also a common pattern is to verify the token signature before storing and using it. You can check out Auth0 blog on where to store it here: https://auth0.com/docs/security/store-tokens
There are several ways to do this. If you are using a state management library like Redux, MobX, Flux etc, then you can put it there.
Another place to store them is in the browser local storage. This will keep the token saved even if the user refreshes the page or open a new tab etc. Yet I am not 100% sure whether it's a safe thing to do.
Or you can attach it to the Rest Client itself. IMO, this is the best way to do it. I will summarize the steps to do that in brief.
Create a Rest Client by wrapping a solution like fetch-api or axios.
Add a module state, where you can store any data
Whenever making a call, check if there is a token, if a token is not there in the state, then authenticate first.
If the token is there, use it to make the api call. If the request fails with a 403(or may be 401. It depends) error, that means the token has possibly expired. So authenticate again and update the token.
Something like this,
class ApiClient {
constructor() {
this.token = null;
}
login(username, password) {
// make the call to login
// set this.token with the response
}
request() {
// Make the API call using the token
}
}
What will happen with a refresh? Then since the token is not there, the authentication will need to happen again. This will not be a problem if you use cookies to manage sessions.
You can put it in Redux store. I think it is the best implementation.
I have implemented an ASP.NET Core MVC Client using Hybrid flow, and I am wondering what the HttpContext.Authentication.GetTokenAsync("access_token") does.
If you need more background on my question:
The instructions for accessing an API from with an ASP.Net Core Client App Controller Action are generally as follows:
var accessToken = await HttpContext.Authentication.GetTokenAsync("access_token");
var client = new HttpClient();
client.SetBearerToken(accessToken);
var response = await client.GetAsync("http://localhost:5001/api/stuff");
There is magic in httpContext.Authentication.GetTokenAsync("access_token") :-)
I am wondering what this function might be doing. Is it decrypting the access token from a cookie in the MVC App Domain? ... from the ID4 Domain?
I am sorry but I have been unable to find sufficient documentation on what this does or finding the cookie the access token may be in. I have looked here:
https://learn.microsoft.com/en-us/aspnet/core/api/microsoft.aspnetcore.authentication.authenticationtokenextensions
Does anyone know what it does? A link to more thorough documentation is a totally appreciated answer.
TU!
You can store arbitrary tokens in your authentication cookie in and that method simply returns one with a given name. Actually setting that would have happened during the sign in process. So in short, it comes from the authentication cookie for your client application and would typically be set at the point of sign in using IdSrv4.
It's a way for the client webapp to confirm separately whether the user really did authenticate with IdentityServer (the user comes to your webapp, the webapp forwards the user to IdentityServer for authentication). The id_token comes back with the user to your webapp in a browser cookie, basically when your webapp sees that id token, it does an independent check with IdentityServer, and if it represents a valid user authentication, you'll get an access token back. You can use that access token to get user claims from the userinfo endpoint.
After all of the above, you can take one of the claims and use it as a key for your application's roles/permissions.
I'm using adaljs. Everything seems great...I can log in, log out, wonderful.
Now, after an hour...I load up my app again and! NOT so wonderful. I debug and I see that adalAuthenticationService.userInfo.isAuthenticated == false and adalAuthenticationService.profile == undefined.
What do I do when I get this? How do I recover?
When do I use these functions and for what?
acquireToken
clearCache
clearCacheForResource
getCachedToken
getResourceForEndpoint
getUser
logOut
logIn
logOutInProgress
Most importantly, WHY are these not explained in detail (or even in brief!) on the adaljs repository?
Let's turn this into a wiki about adaljs functions and properties. We all want to know what they do, what they are for, and how to use them.
Edit
In my app.js, I have this code for handling authentication:
if (adalAuthenticationService.userInfo.isAuthenticated && adalAuthenticationService.userInfo.profile) {
var great = "everything is awesome";
_ld.extend($scope.user,adalAuthenticationService.userInfo);
$scope.successFullyLoggedIn($scope.user);
} else if(!adalAuthenticationService.userInfo.isAuthenticated && !adalAuthenticationService.userInfo.profile) {
adalAuthenticationService.clearCache();
adalAuthenticationService.login();
} else {
adalAuthenticationService.clearCache();
adalAuthenticationService.logOut();
}
The tokens that adal.js gets from AAD expires after every one hour. If you are using angular wrapper then adal will be able to automatically renew the tokens as long as there is a valid user logged in. If you are not using angular wrapper, then application has to take the responsibility of renewing the tokens, that is where the apis will come handy.
I will try to explain what each one of them do:
acquireToken: This is one of the main methods. Takes 2 parameters: resourceId and callback. ResourceId is the app id of application on azure portal. Adal first looks into cache to check if there is token present already. If not, it sends a request to AAD to get a new token. It passes the token or the error to the callback, which has a signature like this: callback(err, token).
clearCache: delete all items in the browser storage that adal stored. Kind of a fresh start.
clearCacheForResource: I am assuming you are using experimental version because this api is not part of released 1.0.12 version. This basically deletes the cache entries for a specific resource id.
getCachedToken: Looks into the caceh and returns the token or null for the given resource.
getResourceForEndpoint: This is useful when using angular wrapper. This looks into the endpoints mapping that user provided at the time of initializing adal. The purpose of this method is to resolve a url into resourceId which can then be fed to acquireToken method.
getUser: current logged in user object or null.
logOut: logs out the user, clears cache and redirect the user to postlogoutredirecturi (if specified), otherwise redirects the user to redirecturi.
login: logs in the user, creates the user object (which can be accessed using getUser), saves the id token in the cache. It also calls the callback that you have on application level on config object when initializing adal.
logOutInProgress: Do you mean loginInProgress? That is just a flag to use internally to see if there is an active login in progress.
Unfortunately, we do not have api guides, that can help people understand our apis better. I will bring this to team's notice. Thanks.
Back to your question: you can use getUser() to get the user object. If it is null, then call logIn() method to log in the user. If user.userName is not null but user.isAuthenticated is false, this means, the token has expired, call acquireToken method and pass clientId of the application to renew the token. Also, you want to check adalAuthenticationService.usernInfo.profile instead of adalAuthenticationService.profile.
I'm creating an app that prints out a pdf from the server after it has been generated.
When using google cloud print I keep getting:
User credentials required
Error 403
Note: making this print request in the simulating page works fine, but that's because I'm already logged into my google account.
After doing some research I found out I need to use OAuth to get an access token to send with the request to make a print job.
And every single page I can find tells me to redirect me to: https://www.googleapis.com/auth/cloudprint, which gives me a 404 error, neither can I find it in the google playground, and using any older versions of authentication ends up in the request to sign in being flagged as an attack from a hacker.
Is there any way around this?
I was stuck on this for a while. The docs don't tell you which scope to use or how to use it. I haven't implemented a Google API using OAuth2 yet, so I didn't have an understanding of how the scoping works.
It turns out the scope is just the base API route for CloudPrint.
To make sure your refresh_token or access_token is scoped properly to use the CloudPrint API you need to use have the following string in your scope object:
https://www.googleapis.com/auth/cloudprint