Using the Google API .NET client with an existing access token - c#

The use-case is the following: a mobile app is authenticating a user with Google and at some point, we need to publish a user's video to his YouTube account; for practical reasons, the actual publication should be done by the back-end (large files that are already stored there).
As the user is already authenticated by the app, the app just sends the user's access token to the back-end. Now my struggle is to find how to use this access token with the .NET client... So far I've tried to create instances of UserCredential from that access token but that doesn't seem to work. Also we don't need all the token refresh logic provided by UserCredential as we know that the access token is valid at this point.
Any help would be greatly appreciated, thanks!

Technically speaking you could just forward the access token, then when you want to call the api you just add the access token to the header as a bearer token
curl --request POST \
'https://youtube.googleapis.com/youtube/v3/videos?key=[YOUR_API_KEY]' \
--header 'Authorization: Bearer [YOUR_ACCESS_TOKEN]' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{}' \
--compressed
This could be done with manually with .net using a Http client.
However if you want to use the Google .Net client library you could do something like this.
var credential = GoogleWebAuthorizationBroker.AuthorizeAsync(GoogleClientSecrets.Load(stream).Secrets,
scopes,
userName,
CancellationToken.None,
new FileDataStore(credPath, true)).Result;
However you will need to do a few things. First off you need to make your own implmentation of FileDataStore which would accept an access token passed to it. I have a few samples of custom datastores here That you can have a look at they may help.
The second issue is that the client id and client secrete that you pass to the Google .net client library will need to be the same one that was used to create the access token to begin with. I am not 100% sure if this will be an issue as you are not passing a refresh token so the client library wont need to refresh the access token it just needs to use it.
There are other ways to create dummy credentials object for use with the Client library but this is the one that i have used in the past.
I dont personally think its a good idea for you to be passing access tokens around between servers in this manner. You really should have the user authorize your app properly.

Related

Basic Authorization in header vs Username and password in body

I am facing two different situations . First method i can send username and password in body as model . Second method is to use basic auth in Header . Both methods are working fine.
Both methods are used only for first call just to authenticate, and the api returns a jwt token.
First Method:
curl -X 'POST' \
'https://localhost:7122/api/Authentication/token' \
-H 'accept: text/plain' \
-H 'Content-Type: application/json' \
-d '{
"userName": "test",
"password": "test"
}'
Second Method:
curl -L -X POST 'https://localhost:7122/api/Authentication/token' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-H 'Authorization: Basic ZzI0N2NmbnlwYzV3cmszaHAwZnU2cTk3N2YzZzYxY2hnODV1NzJzZmJkb3c3LmFwcHMudml2YXBheW1lbnRzLmNvbTowYk9xOHRkMzhMQVF4b3ptaWVqUDYwUzdzQnJkVkQ=' \
--data-urlencode 'grant_type=client_credentials'
Are they rules for what should i use in jwt token?
What is good practice to use?
Just to ensure everyone's on the same page let me outline a typical JWT-authentication workflow here:
User calls an anonymous POST API (no authorization required), with a username and password. API then returns a JWT. That's your Login API at line 3.
All other API calls require authorization, and so the client sends that as Bearer [JWT]. The server then determines if the token is valid and if not returns 401.
As I understand the question, you're asking whether, for (1), it's better to send the u/p through the authorization header using the Basic Authentication protocol (base64 etc) or to just post it in plaintext in the body of the login request.
There are two drawbacks I can see with using the auth header-
Sometimes headers are logged along the way while request bodies rarely are. Grant you, I think it would be unusual (if not unforgivable) for a system to be logging auth headers, but it's possible. The base64 encoding of course provides no security.
I have had difficulty in the past with basic auth headers actually going through. I'll just refer you to this thread which explores some of the possible pitfalls.
Other than the possibe logging issue, I can't think of any inherent issues with using one vs. other though. FWIW, I see APIs all the time that use the plaintext body approach while I've never seen an API that has you log in using basic auth and then returns a JWT.
Hopefully it goes without saying that you MUST ensure your APIs are only accessible through HTTPS. Otherwise you're hosed no matter where you put the password.
That said, if you're designing this from scratch and have access to both ends of the system and they will always be in sync, I'd consider sending a hashed password, regardless whether you use the auth header or POST body. As long as your client and server agree on the hashing method and iteration count, that significantly lowers the impact of that data possibly leaking or being logged somewhere. This would require a little homegrown security work though.
As for your other question,
Are they rules for what should i use in jwt token? What is good practice to use?
Rules? No. Conventions, definitely. Ultimately it's whatever information the application needs to be able to trust the user and give them access. These will be in the form of "claims". There's lots of literature on this but the definitive authority would be the RFC.

Azure Apim Bearer token

Hi guys im following the next tutorial from azure:
https://learn.microsoft.com/en-us/rest/api/apimanagement/current-ga/subscription/create-or-update?tabs=HTTP&tryIt=true&source=docs [Azure create or update suscriptions]
I already made it work,but i dont know from where comes from the Bearer token that the example uses
Can anybody explain to me how i can get that bearer token? actually im planning to use this to create api keys from the back end but i dont exactly know from where i can request that bearer token.
I know it says "Azure Active Directory OAuth2 Flow" in the part of security but can anyone explain to me how that works?
you can get the bearer token by following commands in postman:
post https://login.microsoftonline.com/**{tenantid}**/oauth2/token
From your application you can get the tenant id and client id
Azure portal ->Azure active directory ->your app->overview
client secret:
When you send the command you can get the bearer token.
Reference:
Azure REST API: Create Bearer Token - cloudopszone.com
Alternatively, you can generate the Bearer token/access token using cloud shell from the portal by following the below steps
Sign-in to the Azure portal (https://portal.azure.com)
Open cloud shell, select Power Shell
If you have multiple subscription, using set-Azcontext cmdlet set a particular subscription as context to perform operation on that subscription.
Run the cmdlet Get-AzAccessToken this will give you the access token.
Here is the sample output for reference:

Azure Function with AD auth results in 401 Unauthorized when using Bearer tokens

I have a very simple Azure function in C# for which I've setup Azure AD Auth. I've just used the Express settings to create an App registration in the Function configuration.
public static class IsAuthenticated
{
[FunctionName("IsAuthenticated")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "options", Route = null)]
HttpRequest req,
ILogger log)
{
return new OkObjectResult("You are " + req.HttpContext.User.Identity.Name);
}
}
When I access the function in my browser everything works as expected (if not logged in I have to login and get redirected to my API). But if I try to access my function anywhere a Bearer token is needed I get an 401 Unauthorized error. Even weirder I also can't execute the function in the Azure Portal.
But the token was aquired without a problem and added to the request:
I've tried a few different things to solve this problem. First I thought maybe it's a CORS problem (since I've also had a few of those) and just set CORS to accept *, but nothing changed.
Then I've added my API login endpoints to the redirect and tried setting the implicit grant to also accept Access tokens, it's still not working.
Is there anything I've overlooked? Shouldn't the App registration express config just work with azure functions?
EDIT:
Putting the URL to my function app in the redirects as suggested by #thomas-schreiter didn't change anything (I've tried the config in the screenshot and also just putting each of those values on it's own).
EDIT 2:
I've now also tried to aquire an Bearer token the manual way with Postman, but I still run into a 401 when calling my API.
UPDATE 2020-05-12: According to ambrose-leung's answer further below you can now add a custom issuer URL which should potentially enable you to use v2 tokens. I haven't tried this myself, but maybe this will provide useful for someone in the future. (If his answer helped you please give him an upvote and maybe leave a comment 😉)
This took forever to figure out, and there is very little information about this in the offical documentations.
But it turns out the problem was/is that Azure Functions don't support Bearer tokens generated by the oauth2/v2.0/ Azure API. Since the portal uses those (if your AD supports them) you are out of luck to be able to run the function in there.
This also explains why my postman requests didn't work, because I was also using the v2 api. After switching to v1 I could access my API (Postman doesn't allow you to add a resource_id when you use the integrated auth feature, so I had to switch to handling everything manually).
After that came the realisation that you can't use MSAL either if you are writing a JS client (Angular in my case). So one alternative is ADAL, where the Angular implementation looks kind of awkward. So I decided to use angular-oauth2-oidc which took another hour of tinkering to get it to play nicely with Azure AD.
But after all that I can finally access my API.
I really don't understand why you wouldn't allow users to access Azure Function Apps with Azure AD v2 tokens, but at least this should be so much better documented. But whatever, I can finally go to sleep.
EDIT: After I opend an issue for this, they added a note that v2 isn't supported by Azure Functions, hopefully making life easier for other people.
https://learn.microsoft.com/en-us/azure/app-service/configure-authentication-provider-aad
I managed to get it working through postman using following configuration.
Important lesson was setting in "Allowed token audiences" and "resource" name used in postman to acquire token should be same in this case. I used the same code provided here in question. in this case app registered in Azure AD is a client and resource as well. configuration and testing through postman as follows
Acquire token in postman
Calling azure function using Postman .. Authorization header with bearer token
You can now use v2.0 tokens!
Instead of choosing 'Express' when you configure AAD, you have to choose 'Advance' and add the /v2.0 part at the end of the URL.
This is the code that I use in my console app to present the user with a login prompt, then take the bearer token for use with the Azure Function.
string[] scopes = new string[] { "profile", "email", "openid" };
string ClientId = [clientId of Azure Function];
string Tenant = [tenantId];
string Instance = "https://login.microsoftonline.com/";
var _clientApp = PublicClientApplicationBuilder.Create(ClientId)
.WithAuthority($"{Instance}{Tenant}")
.WithDefaultRedirectUri()
.Build();
var accounts = _clientApp.GetAccountsAsync().Result;
var authResult = _clientApp.AcquireTokenInteractive(scopes)
.WithAccount(accounts.FirstOrDefault())
.WithPrompt(Prompt.SelectAccount)
.ExecuteAsync().Result;
var bearerTokenForAzureFunction = authResult.IdToken;
When setting up your Active Directory authentication on your Function App, set management mode to advanced and fill in the Client ID and Issuer URL as required (and the client secret if necessary).
Importantly, under the Allowed Token Audiences, enter the Application ID URI. This can be found in your registered App Registration (in your AD) under the Expose an API option.
This is what I was missing to get authentication working on my Function App. Before I added that token audience, I would always get a 401 with a valid access token.
This Azure active directory - Allow token audiences helped me get my answer but it took me a while to realise what it was referring to. Remember, it's the Application ID URI that can be found within your App Registration.
I hope it helps!
If you are banging your head against the wall like myself and the original poster, it may be that you are allowing users to sign in from "Accounts in any organizational directory (Any Azure AD directory - Multitenant) and personal Microsoft accounts (e.g. Skype, Xbox)."
Note that as of May 2021, v2.0 works perfectly. If you use https://login.microsoftonline.com/TENANT_ID/oauth2/v2.0/token to get a token with Postman (as described above), you will get a valid token that you can use to auth your AZ Function with.
With that said, IF a user is signed in via a personal account or an account not within your AAD, the token call made by MSAL is requested with the default Microsoft tenant id, NOT your tenant id.
THIS is why I was unable to auth my function. If you are logged in with a user in your tenant's AAD, MSAL is amazing and easy to use and everything will work as described in the documentation.
In the AAD app itself, go to Settings -> Reply URLs and verify that the url of the Function App is in the list, which has the following format: https://mycoolapp.azurewebsites.net. If it isn't, then add it.
If you use slots, you have to add it for both slots.
The only thing i can think of right now is Allowed Audience.
Go to Your Active directory settings and click Advance. Under Allowed Token Audience
Add your exact function url. It might already be there with call back url but Simply replace it with only function base url without any call back as mentioned in the picture.
Make sure when you press ok , you also save your Authentication / Authorization setting to take effect and try again after 1min or so. I tested using PostMan and passing bearer token and it works !
I'm facing the exact same issue today. The issue turned out to be the resource id that I was passing when requesting the access token.
For example, initially I was requesting a token like this, using the function URL as the resource id:
AuthenticationResult authenticationResult = authenticationContext.AcquireTokenAsync("https://myfunction.azurewebsites.net", "myClientAppIdGUID", new Uri("https://login.live.com/oauth20_desktop.srf"), new PlatformParameters(PromptBehavior.SelectAccount)).Result;
While this returned an access token, I was receiving a 401 unauthorized when using the access token to call my function api.
I changed my code to pass my function apps App Id as the resource:
AuthenticationResult authenticationResult = authenticationContext.AcquireTokenAsync("myFunctionAppIdGUID", "myClientAppIdGUID", new Uri("https://login.live.com/oauth20_desktop.srf"), new PlatformParameters(PromptBehavior.SelectAccount)).Result;
Everything works fine now.
For me this was solved when I added the scope: [clientId]/.default
per this article

Dropbox API App Authentication with .NET SDK

I've got a server-hosted .NET app that will need to connect to a single Dropbox account (on a schedule) and just overwrite a file there. In looking at the Dropbox authentication types, it states the following:
App Authentication
This type only uses the app's own app key and secret, and doesn't identify a specific user or team. The app key and secret are transmitted in place of a username and password using "HTTP basic access authentication".
Examples:
When supplying the app key and secret for App Authentication, the app key and secret are given in place of the HTTP username and password, respectively. This can be done either as separate strings, as shown in the first two examples below, or as an base64-encoded Basic authorization string in the Authorization header, as in the third example below.
Example 1:
curl -X POST "https://api.dropbox.com/1/metadata/link" -u "<APP_KEY>:<APP_SECRET>" \
-d
link="https://www.dropbox.com/sh/748egu7925f0gesq/AAHi80RJyhJFfkupnAU0wXuva?dl=0"
Example 2:
curl -X POST "https://<APP_KEY>:<APP_SECRET>#api.dropbox.com/1/metadata/link" \
-d
link="https://www.dropbox.com/sh/748egu7925f0gesq/AAHi80RJyhJFfkupnAU0wXuva?dl=0"
Example 3:
curl -X POST "https://api.dropbox.com/1/metadata/link" \
--header "Authorization: Basic <base64(APP_KEY:APP_SECRET)>" \
-d "link=https://www.dropbox.com/sh/748egu7925f0gesq/AAHi80RJyhJFfkupnAU0wXuva?dl=0"
Great! So I know it can be done without the whole OAuth authentication flow.....However, I can't seem to figure out how to perform App Authentication via the Dropbox.NET SDK by just supplying the AppKey and AppSecret.
Anyone have a code example of how to perform Basic Auth rather than OAuth against Dropbox?

Access Nexmo C# API using OAuth

I am accessing Nexmo API by passing API Key and API Secret. Nexmo uses OAuth 1.0a and I have managed to retrieve the Access Token and Token Secret using DotNetOpenAuth. I have no previous experience with Nexmo. I want to know that how to use Access Token and Token Secret instead of API Key and API Secret. On nexmo website there is not lot of help about this. There is a line written on the bottom of following URl (https://labs.nexmo.com/#oauth) which says "replace "api_key" and "api_secret" by OAuth parameters". I don't know how to do that. Does anyone know?
Hi, I have seen the PHP example but didn't understand much from it. May be I am not getting the idea of OAuth completely. I am using DotNetOpenAuth for signing with Nexmo website. Following is the code I have used so far,
Dim consumer3 As New DesktopConsumer(NexmoDescriptionService.Description, NexmoDescriptionService.TokenManager)
Dim requestToken As String = ""
consumer3.RequestUserAuthorization(Nothing, Nothing, requestToken)
Dim extraParameters = New Dictionary(Of String, String) From {{"request_token", requestToken}}
consumer3 = New DesktopConsumer(NexmoDescriptionService.Description.UserAuthorizationEndpoint, NexmoDescriptionService.TokenManager)
Dim test = consumer3.RequestUserAuthorization(extraParameters, Nothing, requestToken)
Dim request As System.Net.HttpWebRequest = consumer3.PrepareAuthorizedRequest(NexmoDescriptionService.Description.RequestTokenEndpoint, requestToken)
I have used Desktop consumer class because was not able to work with WebConsumer.
There's a screencast here, using PHP, it should be roughly the same for C#. You really don't want to manage the OAuth signing yourself, find a good C# library that does it for you, then just make the request through that.
This example and library may be helpful. At the end of the example, it shows making a call to google after the session has been setup to use the access token. You'll just go through a similar process with Nexmo:
// make a request for a protected resource
string responseText = session.Request().Get().ForUrl("http://www.google.com/m8/feeds/contacts/default/base").ToString();
As to OAuth in genral, the flow is essentially:
Get a Request Token from the Service (in this case Nexmo). That request token is matched to the application credentials you'll already have (you can create these from the Nexmo dashboard).
Redirect to user to authorize that request token. At this point you just wait for the user to be redirected back with an authorized token.
When the user is redirected back with an authorized token, trade that for a long use token, and store the credentials (you'll use those credentials any time you need to make requests on behalf of the user's account).
For the most part, OAuth Client libraries handle all the details, and your application only needs to be concerned with the high level flow.
You can find more information on the OAuth flow at the OAuth site.

Categories

Resources