Issue with jwt-bearer authorization grant in Azure AD - asp.net

There are two ASP.NET Core Web APIs that use bearer token authentication. The services also serve static files which are used to consent the APIs into the directory of a consuming application. So both APIs have implicit flow enabled in Azure AD.
API2 is calling into API1 from the Web API controller using the jwt-bearer grant. API2 has permission to access API1.
A user from a third directory navigates to the SPA served by API2. The user is redirected to Azure AD, signs in and consents the API. The user is redirected back to the SPA application and an AJAX call is made to the API2 web API. From that controller, another call is made to API1. This call is authenticated using the jwt-bearer grant (urn:ietf:params:oauth:grant-type:jwt-bearer).
When the AcquireToken call is made with client credentials for API2 and the JWT token used to call into API2, Azure AD responds with an error:
Microsoft.IdentityModel.Clients.ActiveDirectory.AdalServiceException:
AADSTS50027: Invalid JWT token. AADSTS50027: Invalid JWT token. Token format not valid.
Trace ID: 4031717e-aa0c-4432-bbd1-b97a738d3e6f
Correlation ID: 61ae6cd6-6df6-49ee-9145-c16570c28f7b
Timestamp: 2017-02-13 22:44:01Z ---> System.Net.Http.HttpRequestException: Response status code does not indicate success: 400 (BadRequest). ---> System.Exception: {"error":"invalid_request","error_description":"AADSTS50027: Invalid JWT token. AADSTS50027: Invalid JWT token. Token format not valid.\r\nTrace ID: 4031717e-aa0c-4432-bbd1-b97a738d3e6f\r\nCorrelation ID: 61ae6cd6-6df6-49ee-9145-c16570c28f7b\r\nTimestamp: 2017-02-13 22:44:01Z","error_codes":[50027,50027],"timestamp":"2017-02-13 22:44:01Z","trace_id":"4031717e-aa0c-4432-bbd1-b97a738d3e6f","correlation_id":"61ae6cd6-6df6-49ee-9145-c16570c28f7b"}
Can anyone tell me what this error means? The JWT token itself is correct, it must be one of the claims inside that Azure AD dislikes.
I have the sample apps and repro steps in this github repo.
EDIT
A diagram may clarify what I'm trying to do. It's the interaction #3 that is giving me the error. It uses a ClientCredential with ClientId of API2 and a ClientSecret (or key) and the orange JWT token issued by directory3 with an audience of API2.
The orange JWT token looks like:
eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Il9VZ3FYR190TUxkdVNKMVQ4Y2FIeFU3Y090YyIsImtpZCI6Il9VZ3FYR190TUxkdVNKMVQ4Y2FIeFU3Y090YyJ9.eyJhdWQiOiJmOTJjNGI5MS05NTY3LTRjYjgtOTI4MC0yYmFjNDUyYmZjZTEiLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC9iYWRiODcyNC1jODExLTRlYjEtOTcwZi04YmI4MzU0NTI0OTEvIiwiaWF0IjoxNDg3MDM1MDI5LCJuYmYiOjE0ODcwMzUwMjksImV4cCI6MTQ4NzAzODkyOSwiYW1yIjpbInB3ZCJdLCJmYW1pbHlfbmFtZSI6Im9uZSIsImdpdmVuX25hbWUiOiJ1c2VyIiwiaXBhZGRyIjoiNzMuMTU3LjExMC4xNjQiLCJuYW1lIjoidXNlciBvbmUiLCJub25jZSI6ImRjOTYwMjkzLWQ0MTItNDFmNy1iMGRhLWYzZWM2NTE1ZTM1YSIsIm9pZCI6IjUzMTE1OTY0LWQwOTMtNGM5NS05MDkzLTg0ZjliNzVmYzNlOSIsInBsYXRmIjoiMyIsInN1YiI6IlVjVFVleGJYd1BWYkZ4aGRDUW9MR25vTkdsZnVQWi1feGtaSndIdU9zM1EiLCJ0aWQiOiJiYWRiODcyNC1jODExLTRlYjEtOTcwZi04YmI4MzU0NTI0OTEiLCJ1bmlxdWVfbmFtZSI6InVzZXIxQHppZWtlbmh1aXNBLm9ubWljcm9zb2Z0LmNvbSIsInVwbiI6InVzZXIxQHppZWtlbmh1aXNBLm9ubWljcm9zb2Z0LmNvbSIsInZlciI6IjEuMCJ9.lhwEL3x3Cu66l-Dt-hWmH2DrmCCX2YORGhl4x4_13_lZuUVhMr1OFLUdJ4MZRWG5DJMc8F_SyC4XdDiStwFDaLSI_4L6noXNau3KF6Su3PnqD-FoXoQPtmPPmFrDRZ7nPEtSazEcd9HeSwgVvRZywJRBKQqQQtBGBpS7-Y9kxrO-moUhnBdJJ-gwhu_wxwdEZaOuLs68sZuFaONAunElMKO1iYlC9VHP5xrVzh3ErnRSIp3xmgJNmlbf-9AFUSrjN5UaFjfpGGGJIvoaKbL6rq-J1XNpvKZDFYvoC7RMkqS1KM-lu-EI7-QCksb3NKhTg6J_bz5uxmjYltjKanWbUg

First, to enable the API2 could onbehalfof the user to acquire the token for API1, we need to grant the API1 to API2 when we register the API2 in the Directory2 like below:
Then since the service principal of API1 is also not created in Directory3, we need to sign-in the API1 first to to create the service principal of API1 on Directory3 tenant.
When the users sign-in the SPA from Directory3 and send the request to the API2, in the code you were acquire the token from Directory2. We should acquire the token from the tenant of users(Directory3).
And in the code, you were acquiring the token using the clientId, in this secnario, we should use the ClientCredential like below:
var result = await adal.AcquireTokenAsync(resource, clientCred, userAssertion);
After changing, the code works well for me. Please let me know whether it helps.
In addition, the scenario you are developing is like below and you can refer the detail from this link.

Related

Firebase iOS Auth with Twitter + Make requests on backend (403 status code)

i've succesfully integrated Twitter Auth via my iOS app and firebase, as explained here: https://firebase.google.com/docs/auth/ios/twitter-login
I'm able to get an oauth access token + secret from the user that authorizes the connection via app.
My intention was to use the oauth access token to make requests via the node-twitter-api-v2 library, for example - fetching the user's bookmarks.
I tried using the access token in place of the "bearer token" when initializing the TwitterApi client, but am still getting the error:
Authenticating with OAuth 2.0 Application-Only is forbidden for this endpoint. Supported authentication types are [OAuth 1.0a User Context, OAuth 2.0 User Context].
From my understanding, such requests must be made via a "logged in" client and the v2 api - question is, is there a way to use the already authed user's (via app) token to make the request / log in? This is done via background + backend, so the idea is that there is no UI / callback to make the user go through to create the logged in session.
Any ideas on how to approach this or if it's even possible?
Example code:
//call the new v2 api
const bookmarkedTweets = await this.twitterClient.v2.bookmarks({
max_results: max_fetch_limit,
expansions: ['attachments.media_keys'],
'media.fields': ['preview_image_url', 'url', 'variants'],
'tweet.fields': ['created_at', 'entities', 'attachments', 'author_id', 'conversation_id', 'id', 'text'],
});
Error response:
data: {
> title: 'Unsupported Authentication',
> detail: 'Authenticating with OAuth 2.0 Application-Only is forbidden for this endpoint. Supported authentication types are [OAuth 1.0a User Context, OAuth 2.0 User Context].',
> type: 'https://api.twitter.com/2/problems/unsupported-authentication',
> status: 403
> }
From what i read in twitter docs, once we get the token form user, all we need to do is just call the endpoints with the token as the Bearer, but this does not seem to work (maybe i read instructions wrong).
**
* Create a new TwitterApi object with OAuth 2.0 Bearer authentication.
*/
constructor(bearerToken: string, settings?: Partial<IClientSettings>);
Any help would be greatly appreciated. Thank you

Firebase - Email / Password provider device authorization endpoint

I'm trying to implement OAuth 2.0 device authorization for a Firebase project that uses the Email / Password provider for sign in.
In a response from a previous question I was able to test device authorization using a Firebase Device Flow project and the Github and Google providers successfully.
For each of these providers there is an endpoint that is used to request a device code:
Google https://oauth2.googleapis.com/device/code
Github https://github.com/login/device/code
Facebook has the following endpoint, which I have successfully tested:
Facebook https://graph.facebook.com/v2.6/device/login
Is there an equivalent device code authorization endpoint for the Email / Password provider?
EDIT: Looking at the firebase auth library I don't see a credential method that takes an access token. This implies perhaps this isn't possible. Perhaps something could be built to use the credentialWithLink method; an email would be sent with device id and the sign in would enable the polling client to receive a response with a link.
I ended up building the infrastructure myself by setting up:
Endpoints: to get a device token, sign in to validate the device code, get a custom user token for a device token
Website: for the user to enter in credentials to send to validate the device code
Client app: to request the device token, show the qr code and poll for the user token and swap the custom token using the firebase auth method signInWithCustomToken
I used firestore to store the device tokens and update them with the uid, expiry timestamp and verification state with each step.

What is the OpenID Connect access token for?

The OpenID Connect JWT token contains both an id_token and an access_token (Like "access_token": "SlAV32hkKG"). What is the access_token for?
ANSWER EXAMPLE
Just adding an example to complement the answers taken from this linked article
User Info Endpoint Request
GET /userinfo HTTP/1.1
Host: openid.c2id.com
Authorization: Bearer SlAV32hkKG
User Info Endpoint Response
HTTP/1.1 200 OK
Content-Type: application/json
{
"sub" : "alice",
"email" : "alice#wonderland.net",
"email_verified" : true,
"name" : "Alice Adams",
"picture" : "https://c2id.com/users/alice.jpg"
}
The answer to your question lies in the section 5.3 and 16.4 of the specification. The access token is used to access the userinfo endpoint which is a protected resource.
16.4. Access Token Disclosure
Access Tokens are credentials used to access Protected Resources, as defined in Section 1.4 of OAuth 2.0 [RFC6749]. Access Tokens represent an End-User's authorization and MUST NOT be exposed to unauthorized parties.
[...]
5.3. UserInfo Endpoint
The UserInfo Endpoint is an OAuth 2.0 Protected Resource that returns Claims about the authenticated End-User. To obtain the requested Claims about the End-User, the Client makes a request to the UserInfo Endpoint using an Access Token obtained through OpenID Connect Authentication. These Claims are normally represented by a JSON object that contains a collection of name and value pairs for the Claims.
tl;dr - Access token grants authorization to access a protected resource where the ID token is consumed by the client for authentication.
Access token
Being an extention to OAuth2.0, OpenID Connect keep tokens/prameters defined in OAuth2.0 specification. Access token is one such thing. As defined by the protocol, access token is used to access protected resources. It replaces user credentials, manually generated tokens or security keys which were used in good old days (ex:- Think about basic authentication).
Note the access token could be an opaque string. Which means it's nothing that could be consumed by the client which recieves it. But the authorization server knows what it is. For example, introspection endpoint (RFC7662) can be used to validate the validity of an access token. And access token can be a JWT too depending on the usage and implementation.
ID token
This is what OpenID Connect introduced to OAuth2.0. ID token is a JWT and it is consumed by client to authenticate the end user(the resource owner). By validating an ID token, client have the ability to authenticate. Due to this fact, one can argue it surves one time usage.
Also note that in some implementations, ID tokens are being used as bearer tokens. That mean, ID token used like an access token for authentication and authorization.

Asp.Net - Jwt Bearer Authentication: Invalid Signature

I obtain an access_token and id_token from AzureAD for my app, which is using OAuth2 with the implicit flow. This is a sample URL where I obtain the tokens:
https://login.microsoftonline.com/my_tenant_id/oauth2/v2.0/authorize?response_type=id_token+token&client_id=my_client_id&state=some_state&redirect_uri=http%3A%2F%2Flocalhost%3A4200%2Fsign-in&scope=openid%20https%3A%2F%2Fgraph.microsoft.com%2Fuser.read&nonce=some_nonce
The scope is openid https://grap.microsoft.com/user.read.
The response_type is id_token+token.
I also have a Asp.Net backend, I want to secure. So I use the Authorize Attribute for my controller and send a token in the header as like this: "Authentication : Bearer THE_TOKEN".
My configuration in Startup.cs looks like this:
app.UseJwtBearerAuthentication(new JwtBearerOptions
{
Authority = string.Format("https://login.microsoftonline.com/{0}/v2.0/",
"d67853c3-db96-4dac-a37b-f2bfb12b42d1"),
Audience = "8422b3fb-5612-4fdd-a90f-707d7218de57"
});
From what I have read, the access token should be used for this, and the id_token should not leave the frontend. But authentication in the backend only works with the id token in my case. The access_token can not be signed Bearer error="invalid_token", error_description="The signature is invalid".
Looking at the access_token in jwt.io, I see the tokens have different audiences and issuers. The access_token for example has this
"aud": "https://graph.microsoft.com",
"iss": "https://sts.windows.net/d67853c3-db96-4dac-a37b-f2bfb12b42d1/",
whereas the id token has this
"aud": "my_client_id",
"iss": "https://login.microsoftonline.com/my_tenant_id/v2.0",
So it seems to me, the access_token was somehow issued for the Graph API. Would be glad if someone could tell me, what i am doing wrong or how I can try to solve my issues.
edit:
It WAS working as intended before when I used the scope openid profile. But due to changes in Azure, this scope is not valid anymore and Microsoft directed me to use the scope mentioned above.
As you mentioned, the access token you requested is for the Microsoft Graph. And the id_token is only for the client to authenticate the user instead of for the resource server.
To protect the web API using the Azure AD V2.0 endpoint, we can acquire the access token for the web API like request below:
https://login.microsoftonline.com/common/oauth2/v2.0/authorize?response_type=token&client_id={client_id}&scope=api://{client_id}/access_as_user&redirect_uri={redirect_uri}
And here is the code using protecting the web API via Azure AD V2.0 endpoint:
public void ConfigureAuth(IAppBuilder app)
{
System.Diagnostics.Trace.TraceWarning("Hello");
var tvps = new TokenValidationParameters
{
// The web app and the service are sharing the same clientId
ValidAudience = clientId,
ValidateIssuer = false,
};
// NOTE: The usual WindowsAzureActiveDirectoryBearerAuthenticaitonMiddleware uses a
// metadata endpoint which is not supported by the v2.0 endpoint. Instead, this
// OpenIdConenctCachingSecurityTokenProvider can be used to fetch & use the OpenIdConnect
// metadata document.
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions
{
AccessTokenFormat = new JwtFormat(tvps, new OpenIdConnectCachingSecurityTokenProvider("https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration")),
});
}
}
More detail about protecting the web API via Azure AD V2.0 endpoint, you can refer the document below:
Calling a web API from a .NET web app

Google Sign-In: exchange code for access token and ID token

I am using client ID for Android/iOS to authenticate users with Google Sign-In. This is working fine and I receive a code after successful authentication.
Now for some reason I would like to validate this code in the server-side with google and obtain access token. But we do not have any secret key for client ID(s) for Android/iOS. How can I verify the code and get the access token?

Resources