Graph SDK OAUTH ADAL client credentials for reuse? later - wpf

So we have an application that allows you to create a xml file that runs the app again at a later stage (which may or may not have a user in attendance). Files are stored on the user cloud drive platform of choice. So the process is
Workflow 1
Authenticate to cloud with User 1 details/input
Select files to Download and use
Save and encrypt file metadata and Refresh token to xml file. (app workflow 1)
Workflow 2 ( can be repeated multiple thousands of times)
Send xml file to another pc with User 2. (either by email or remotely through a console
that pc then runs under user 2
start app
App authenticates automatically using refresh token saved in xml file with no user input (as there is a very high chance of the user who created workflow 1 not being in the same city as where workflow 2 is running
Downloads files
applies files (app workflow 2)
PROBLEM
all other platforms we cater for (Dropbox and google and onedrive) gives us access to the refresh token and allow us to authenticate with it again , however the onedrive for business (graph sdks) give us a Token cache which is session based?
Questions
So I need to know how I can get the refresh token from the Token Cache so we can reuse it at a later stage. (yes I'm aware that it will expire after 6 months which is acceptable) .
When i have the refresh token how do initiate a call to refresh the token
Further note - I have managed to handle all platforms before Within silverlight (where the sdks are not supported) through directly calling the rest api calls but we are converting our solution to WPF and would want to use the sdks
thanks

I assume you were developing Microsoft Graph SDK when you mentioned graph sdks.
AFAIK, this library does not include any default authentication implementations. Instead, the user will want to authenticate with the library of their choice, or against the OAuth endpoint directly, and built-in DelegateAuthenticationProvider class to authenticate each request.
And if you were authenticating Azure AD with Active Directory Authentication Library, you can use the default token cache which use memory to store the cache or you can implement the token cache based on your requirement.
So I need to know how I can get the refresh token from the Token Cache so we can reuse it at a later stage. (yes I'm aware that it will expire after 6 months which is acceptable) .
When you using the ADAL library, there is no need to get the refresh token manually, it will handle for us to renew the access token if the refresh token is existed.
When i have the refresh token how do initiate a call to refresh the token
If you want to perform the request yourself to refresh the access token, you can refer the request below, and more detail you can refer this document.
POST /{tenant}/oauth2/token HTTP/1.1
Host: https://login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded
client_id=6731de76-14a6-49ae-97bc-6eba6914391e
&refresh_token=OAAABAAAAiL9Kn2Z27UubvWFPbm0gLWQJVzCTE9UkP3pSx1aXxUjq...
&grant_type=refresh_token
&resource=https%3A%2F%2Fservice.contoso.com%2F
&client_secret=JqQX2PNo9bpM0uEihUPzyrh // NOTE: Only required for web apps

OK so the answer is taking the tokencache from the PublicIdentityApp and serializing as below.
var tokenCache = _app.UserTokenCache;
var tokenBytes = tokenCache.Serialize();
var tokenString = Convert.ToBase64String(tokenBytes);
And deserializing it later.
_app = new Microsoft.Identity.Client.PublicClientApplication(ClientID);
var array = Convert.FromBase64String(bytestring);
_app.UserTokenCache.Deserialize(array);
authHelper = new AuthenticationHelper(_app);
var authorise = await authHelper.GetTokenForUserAsync()

Related

How to get user info with a valid Bearer Token?

At work we are making an SPFx Web Part React client app that deploys to SharePoint as a Web Part. Our back-end is a ASP.NET Core 2.2 Web API that is secured using Azure Portal's built in Authentication feature. The front-end is using AadHttpClient that magically handles the authentication by taking the context of the current page (SharePoint) that has the user already logged in. Doing so, silent authentication occurs and the API call is successfully made with authentication successfully passed. The AadHttpClient is supposed to magically bundle up the token in the request header that gets sent to the back-end Web API. I still need to debug the live development app and see how to retrieve the Bearer Token in the back-end Web API. These are my next probable steps?
Would I just probably use 'string bearerToken = Request.Headers.....;' or 'string bearerToken = Request.Headers["KeyValue"]' to get the token itself?
Assuming I can get this Bearer Token, how can I check the caller's user information? Is it just var userName = User.Identity.Name;? Or would I or could I use the token and some how make a call to Microsoft Graph API to view the user's info?
If you are using ASP.NET Core and using default authentication then things are bit easier. From documentation you can see that several tokens are injected in the request header based on Identity provider so in your case you have to look for following headers which Azure AD injects. These headers would contain ID Token which you would need to verify the claims and get user information.
X-MS-TOKEN-AAD-ID-TOKEN
X-MS-TOKEN-AAD-ACCESS-TOKEN
X-MS-TOKEN-AAD-EXPIRES-ON
X-MS-TOKEN-AAD-REFRESH-TOKEN
Ideally all the claims are injected automatically in ClaimsPrincipal
you can find more here
Official Docs
How To extract Token

Scope for multiple web apis

I have 2 web apis (A and B) on my b2c. Each one of them publishes their own permissions respectively (scopeA1, scopeA2) and (scopeB1, scopeB2).
On my web application (which already configured and have granted access permission on both apis and the 4 scopes), in order to get authorization code for both apis during authentication, I tried to set my OpenIdConnectAuthenticationOptionsin scope property to include the 4 scopes.
I got an error AADB2C90146: The scope 'scopeA1 scopeA2 scopeB1 scopeB2 openid offline_access' provided in request specifies more than one resource for an access token, which is not supported.
While if I specify only scopes for web api A or B, then it works as per this link
How can I get my web app to use both web apis even with granted permissions for both
Thanks for help
If the two web APIs are separate applications in Azure AD, then you need to request access tokens separately for them.
I'm not familiar with the sample you used as a starting point, but it looks like these lines are where you need to make your change:
// Retrieve the token using the provided scopes
ConfidentialClientApplication app = new ConfidentialClientApplication(authority, Startup.ClientId,
Startup.RedirectUri, credential,
new NaiveSessionCache(userObjectID, this.HttpContext));
AuthenticationResult result = await app.AcquireTokenSilentAsync(scope);
accessToken = result.Token;
You should create an app instance for each of your APIs, and acquire a token for each of them. Then, when you call the APIs somewhere else, use the correct access token in the Bearer authentication header.
I had the same issue and asked a similar question Extend MSAL to support multiple Web APIs
but i have not had an answer, basically to get around it in the short term i have made both my API's use the same authorization client ID + secret and therefore I can reuse the same scopes accross my APIS
its not what i want but if you want to use Azure AD B2C you need to get used to compromising for a while until the support is there
-- I would also say you are using an older version of MSAL which i am also using, im waiting until the version 1 release before upgrading again.
The github talks about using this format
https://github.com/AzureAD/microsoft-authentication-library-for-dotnet
Step 1: Add MSAL to your Solution/Project
Right click on your project > Manage packages.
Select include prerelease > search msal.
Select the Microsoft.Identity.Client package > install.
Step 2: Instantiate MSAL and Acquire a Token
Create a new PublicClientApplication instance. Make sure to fill in your
app/client id
PublicClientApplication myApp = new PublicClientApplication(CLIENT_ID);
Acquire a token
AuthenticationResult authenticationResult = await
myApp.AcquireTokenAsync(SCOPES).ConfigureAwait(false);
Step 3: Use the token!
The access token can now be used in an HTTP Bearer request.

Google OAuth2 flow and id_token refresh

I am having troubles in implementing OAuth in the right way.
I use a client/API architecture (Angular for front and Node.js for back) and I would like user to sign in using Google OAuth authentication only.
Here is what I think is the right way for the moment (tell me if I misunderstood something) :
Angular open a Google popup asking user's consent.
Once the user agree, Google Authorization server sends back to angular a verification code.
This verification code is forwarded to an API endpoint.
Then, the API asks Google Authorization server to exchange this code for an access_token, an id_token and a refresh_token.
Google sends those 3 tokens.
The API uses access_token to retrieve user from Google API
The API persists the user
Here is the little dillema, in my opinion, the access_token and refresh_token should be stored into the database and the id_token should be sent back to Angular client.
This way, it would allow the API to ask for resource in Google API and if the token expires it can still ask for a new token thanks to the refresh_token.
Client-side, the id_token is embedded in all requests thus allowing the API to identify the client and verify his authentication with Google certs from https://www.googleapis.com/oauth2/v3/certs.
Supposing this is right way to use tokens, how could I deal with id_token expiration since client does not have any refresh token ?
Thanks !
I do it slightly different (I have the same basic architecture though).
Angular decides the user needs to log in and displays a login popup.
The url in the login popup is not serviced by angular, but is instead directly run off of the backend server: /auth/google . (I use hapijs and bell, personally).
/auth/google is serviced by a bell plugin and initiates the OAUTH dance.
the end of the OAUTH dance results in my node server generating a local token (I just generate random bytes and store them in redis mapped to user ids)
because the initial login popup was created by window.open, the success page (generated on the api side rather than in angular) can use window.opener.postMessage to communicate the token back to the angular runtime.
This way, all my sensitive google credentials (the user's oauth token, refresh token if needed, and my application's api ID and secret) are only on the server, except for during the OAUTH dance relay when they're in a URL string during the client redirects. This is reasonably secure.
Then for all the actual user interactions with the api, I use the token I generated in step four to authenticate. This could be a JWT if you wanted, but I don't do it that way; I just use redis to map from 'longrandostring' -> userId. That lets me (for example) force everyone to re-login if I wipe the redis database that has all the tokens stored, or I can write a lua script to delete all the entries that map to a certain userid.
If you need a refresh token, you can set access_type=offline in the initial request to oauth2/auth, and you'll get a refresh token as part of the response, unless you've previously gotten a refresh token. You can then persist it on the server side and get new access tokens as needed. If you set approval_prompt=force as well, you'll force a new consent screen and be guaranteed a refresh token (but after some small number of refresh tokens granted to a user, older ones expire on the same application so it's best to only request them if really needed).

OAuth 2.0 with GMAIL API using

I am trying to create a sample program for Install Application to access google mail api using oAuthentication. But I have a query before start working on it.
I read on most of doc and following this link https://developers.google.com/identity/protocols/OAuth2InstalledApp
First we need to request for token by providing ClientID and SecretKey
That will return Token in response that Token is pass to other google service which we want to access.
During this process code open the browser (Single time) to get token id. It can not happen without browser.
Can't we do http request to google then get respond from it without using browser, like access any rest api we do?
From Google's Using OAuth 2.0 to Access Google APIs:
The authorization sequence begins when your application redirects a
browser to a Google URL; the URL includes query parameters that
indicate the type of access being requested. Google handles the user
authentication, session selection, and user consent. The result is an
authorization code, which the application can exchange for an access
token and a refresh token.
The application should store the refresh token for future use and use
the access token to access a Google API. Once the access token
expires, the application uses the refresh token to obtain a new one.
You have no choice but to redirect the user to Google the first time the user is using your application. However, you can ask for a refresh token that you can use to refresh the access token after this first login, which usually expires after one hour.

when using mirror api, how do i handle access token expiration

I am building a glass app using the PHP sample app as reference.
To my understanding, the glass app is a web app which is user facing. When the user visit the web app, they will authorize the web app (using oauth2) to access their resources, and once authorization succeeded the web app will get an access token, which is then saved in a sqlite database (there's this store_credentials() function which stores the access token).
So if I have 100 users who visit the web app and register, the database will hold 100 access tokens for these users. Let's say I have some backend code which pull from a RSS feed every hour, and whenever I find there's a new story I will push it to all registered users. Let's say I have a cron job which does this, when when this job is triggered, I will find all the access tokens in the database and use them to make mirror API calls to insert cards. But what if some of the access token is expired when I am trying to make the mirror API call? It seems I will need to ask user to re-authorized, but at this point I am not interacting with the user. If I have a refresh token, I may be able to call oauth again to get a new access token.
Thanks.
You pretty much answered your own question - when you request permission using OAuth, you should also request "offline" access. The first time you do this for each user it will give you a refresh token along with your access token, and you should store both. If you did not request offline access initially, you will need to revoke the tokens that have been granted and re-grant them with offline access.
If the sample app you're referring to is the one at https://github.com/googleglass/mirror-quickstart-php, all this should be done for you already with the libraries included. The credentials returned from $client->getAccessToken() in oauth2callback.php should include both the access and refresh tokens, and these are saved in that same file by calling store_credentials(). The client libraries should check if the access token has expired and, if so, it gets a new one with the refresh token before making the call.
You may want to take a look at the contents of the credentials object at these various points and make sure there is a refresh token. If not, try revoking all the tokens and starting again, since it sounds like the first time you authorized the client you did so without requesting offline access.
If you are doing this yourself, best practice is to either refresh the access token if it has expired or is about to expire (since there may be some delay) before use, or (even better) attempt to make the call with an access token and, if it fails with an authentication error, get a new access token via the refresh token and try again.

Resources