How to sign in with provider's token Without the mobile SDK - azure-api-apps

Azure API apps and Azure mobile apps have the same Auth. The azure back-end normally keeps provider's token, for instance, access token to twitter, and issues a different access token for the client to access azure service.
This question talks about the process.
There is an alternative method for signing in, a client can obtain the provider's token on it's own accord. Then it can use that token with Azure Api App or Azure Mobile App.
When you are using the Azure Mobile App client SDK there is an overload on the .Login() function you can use.
I would like to know how I can use Twitter's, or any other provider's, token to sign into my Azure-Api-App without the Mobile App SDK.
There seems to be no documentation on the matter. Where do I send the HTTP request and what headers should it have?

You can log in with Twitter credentials without using the Mobile Client SDK by issuing the following HTTP requests to your app:
POST /.auth/login/twitter
Content-Type: application/json
Content-Length: XXX
{"access_token":YYY, "access_token_secret":ZZZ}
App Service will validate the credentials, store your tokens in its token store, and then return a JSON payload back to your HTTP client which contains the authentication token. The success response will look something like this:
{
"user": {
"userId" : "<userId>"
},
"authenticationToken" : "<jwt_token>"
}
You can then set an x-zumo-auth request header with the jwt_token value to make authenticated calls to your REST APIs. For example:
POST /api/doSomethingThatRequiresAuth
Content-Length: 0
X-ZUMO-AUTH: <jwt_token>
The process is the same for other providers, except the payload of the /.auth/login/provider might be different. The design is derived from the old Mobile Services Client-Directed Login design, so for the most part you can infer what the payload looks like from that documentation.

Related

Securing a web app against authorization API without revealing credentials

I have a web app MyWebApp.
And two APIs: MyAuthAPI and MyServiceAPI, both RESTful NodeJS. MyAuthAPI uses HashiCorp Vault as a token store with OAuth2.
MyServiceAPI has CRUD operations available to authenticated clients.
There is no human login required (or desired) on MyWebApp. Any human can access MyWebApp through a browser and run the service.
At present, this is the (very insecure) flow:
MyWebApp sends clientid and clientsecret to MyAuthAPI to retrieve token. This token is then used for communicating with MyServiceAPI.
The obvious downside is that anyone can capture the clientid and clientsecret by simply looking in developer tools in a web browser. They could then use those to authenticate with MyAuthAPI, generate their own token, and make calls to MyServiceAPI without MyWebApp being involved.
So how do I best secure the entire application so that MyWebApp is safely and robustly authenticated without revealing the credentials?
Thanks.
ETA:
I want to be able to authenticate MyWebApp with MyAuthAPI and then use the generated token to connect to MyServiceAPI. But I don't want it to be possible that anyone can intercept those credentials - currently they can be see in the request header as "Authorization: Basic "
The MyServiceAPI endpoints must be secured so that only authenticated clients are able to access them. But when that client (MyWebApp) is a public website, how do I authenticate without making the credentials visible?
ETA2:
https://mywebapp.com is MyWebApp which is a React application.
https://myauthapi.com hosts MyAuthAPI
https://myserviceapi.com hosts MyServiceAPI
When I load mywebapp.com in a web browser, it authenticates with myauthapi.com/oauth/token to get a token. At present it does this by sending the creds in the header Authorization: Basic
The token that is returned is then saved.
The web application then tries to get the data from an endpoint on MyServiceApi using this token:
Authorization: Bearer
GET https://myserviceapi.com/objects
or POST myserviceapi.com/objects
or GET myserviceapi.com/objects/objectid
or DELETE myserviceapi.com/objects/objectid
MyServiceAPI verifies the token with MyAuthAPI, but that isn't public-facing, so there's no issue there.
The issue is that, as you can see from the attached screenshot of the Developer Tools console in Chrome, anyone using the web application can see the Authorization header containing the credentials, and could then use these credentials to programatically gain access to the auth API to generate a token which can then be used on the service API endpoints.
I want to restrict all access to the API servers to only come from specific applications, such as MyWebApp, on mywebapp.com.
First, I think this question could better be asked in https://softwareengineering.stackexchange.com/.
Second, where MyWebApp is deployed? How it is being used? If it works with https, then the body is encrypted, and when you send the clientId and clientSecret, you should send it in the body, so users will not be able to see them.
Client Credentials Grant should only be used by confidential Clients. Thats because you can't hide the client_secret on non confidential Clients. Your frontend seems to be a non confidential Client.
Normally you should use the Authorization Code Grant with PKCE. But you would need users to authenticate themselves for that.
Feels like you need an architecture design based on standard flows, since OAuth should work like this:
Web app signs user in via an Authorization Server, using Authorization Code Flow (PKCE)
Web app gets tokens from the Authorization Server
Web app calls API with an access token
API validates token using data from the Authorization Server
API then trusts claims in the access token and uses them for authorization
See my Initial HTTP Messages blog post for an example of how this looks.

Can a browser app (spa) access MS Graph without a logged in user?

I can register an app in Azure as 'Web' application, specify the permissions it needs to read from Graph, consent to the permissions as an admin, create a client secret.
I try using the client secret in the app to request an access token. But MS identity platform rejects grant_type=client_credentials /token endpoint requests that come from a browser.
But how does it even know the caller is a browser? The same requests works when it is sent via Postman!
Obviously, CORS makes the difference: When a browser executes the request from myserver/myapp.js, it sets the 'Origin' header in the request going to login.microsoftonline.com and, by registration as a 'Web' app, does not send back an Access-Control-Allow-Origin response to the browser - the browser refuses to get the response. On the other hand, when Postman executes the request, it uses it's cloud agent to run the request. The agent doesn't send an 'Origin' header and doesn't check the response header.
Is there a different way an app in a browser can call Graph without a logged in user?
The answer is No. based on this Azure AD official doc, if you want to get an access token on SPA, only OAuth 2.0 implicit grant flow and OAuth 2.0 authorization code + PKCE flow are supported but both of these two flows require users' interaction to login.
Cross-origin resource sharing (CORS) is a browser mechanism. Your request is blocked by your browser, Azure AD endpoint does not care about what kind of app sends the request.
This is a similar question answered by MVP: #juunas.

Get a msgraph access token using another access token

I created an Azure app for which I created custom scopes through the "Expose API" screen. I have a single page application that uses the code flow to login into the application requesting these custom scopes. On my ASP.NET Core web application, I added the authentication layer to use JWT as bearer. Works pretty well and I can secure my web APIs as expected.
Now, I also added API permissions for msgraph because I want to be able to create online meetings with it. The flow would be:
The user logs in using my custom scope audience
He sends a call to a secure web api to create something
Something is added to the database
An online meeting is created on behalf of the user
The "issue" is that the access token received by my web API is not valid for msgraph, I need to get one, on behalf of the user related to the access_token. However, I have no idea how to get a msgraph token using another access_token. I don't even know if that's possible.
However, if it's not possible, how am I supposed to create the online meeting from the .NET Core part of my application ?
Take a look at the On Behalf Flow, specifically the example "First case: Access token request with a shared secret". You can use your existing access token as the assertion parameter.
The following HTTP POST requests an access token and refresh token with user.read scope for the https://graph.microsoft.com web API.
//line breaks for legibility only
POST /oauth2/v2.0/token HTTP/1.1
Host: login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded
grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer
&client_id=2846f71b-a7a4-4987-bab3-760035b2f389
&client_secret=BYyVnAt56JpLwUcyo47XODd
&assertion=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6InowMzl6ZHNGdWl6cEJmQlZLMVRuMjVRSFlPMCJ9.eyJhdWQiOiIyODQ2ZjcxYi1hN2E0LTQ5ODctYmFiMy03NjAwMzViMmYzODkiLCJpc3MiOiJodHRwczovL2xvZ2luLm1pY3Jvc29mdG9ubGluZS5jb20vNzJmOTg4YmYtODZmMS00MWFmLTkxYWItMmQ3Y2QwMTFkYjQ3L3YyLjAiLCJpYXQiOjE0OTM5MjA5MTYsIm5iZiI6MTQ5MzkyMDkxNiwiZXhwIjoxNDkzOTI0ODE2LCJhaW8iOiJBU1FBMi84REFBQUFnZm8vNk9CR0NaaFV2NjJ6MFFYSEZKR0VVYUIwRUlIV3NhcGducndMMnVrPSIsIm5hbWUiOiJOYXZ5YSBDYW51bWFsbGEiLCJvaWQiOiJkNWU5NzljNy0zZDJkLTQyYWYtOGYzMC03MjdkZDRjMmQzODMiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJuYWNhbnVtYUBtaWNyb3NvZnQuY29tIiwic3ViIjoiZ1Q5a1FMN2hXRUpUUGg1OWJlX1l5dVZNRDFOTEdiREJFWFRhbEQzU3FZYyIsInRpZCI6IjcyZjk4OGJmLTg2ZjEtNDFhZi05MWFiLTJkN2NkMDExZGI0NyIsInV0aSI6IjN5U3F4UHJweUVPd0ZsTWFFMU1PQUEiLCJ2ZXIiOiIyLjAifQ.TPPJSvpNCSCyUeIiKQoLMixN1-M-Y5U0QxtxVkpepjyoWNG0i49YFAJC6ADdCs5nJXr6f-ozIRuaiPzy29yRUOdSz_8KqG42luCyC1c951HyeDgqUJSz91Ku150D9kP5B9-2R-jgCerD_VVuxXUdkuPFEl3VEADC_1qkGBiIg0AyLLbz7DTMp5DvmbC09DhrQQiouHQGFSk2TPmksqHm3-b3RgeNM1rJmpLThis2ZWBEIPx662pjxL6NJDmV08cPVIcGX4KkFo54Z3rfwiYg4YssiUc4w-w3NJUBQhnzfTl4_Mtq2d7cVlul9uDzras091vFy32tWkrpa970UvdVfQ
&scope=https://graph.microsoft.com/user.read+offline_access
&requested_token_use=on_behalf_of

How can I use azure ad access token which is got from SPA to protect backend api?

I want to use azure AD as authentication.
If user who is in certain organization logged in from SPA, and give access token to backend, then I want to permit access from SPA.
So, I want to check if token passed from SPA is valid or not.
How can I do this?, Or Can I do this?
I want to build backend server with node.js app, and deploy backend app to app service or Azure Container Registry.
I think bearerStrategy would work.
Ref https://github.com/AzureAD/passport-azure-ad
BearerStrategy uses Bearer Token protocol to protect web resource/api.
It works in the following manner: User sends a request to the
protected web api which contains an access_token in either the
authorization header or body. Passport extracts and validates the
access_token, and propagates the claims in access_token to the verify
callback and let the framework finish the remaining authentication
procedure. On successful authentication, passport adds the user
information to req.user and passes it to the next middleware, which is
usually the business logic of the web resource/api. In case of error,
passport sends back an unauthorized response.
In the past, there was an ADAL version for node apps. I don't know if it's still valid or not, but here are useful links:
https://medium.com/#liangjunjiang/verify-and-decode-azure-activity-directory-token-bc72cf7010bc
https://learn.microsoft.com/en-us/azure/active-directory/develop/authentication-flows-app-scenarios

OpenID Connect - Implicit Flow with Javascript app using JWT to authenticate with a REST API

I am developing a Javascript app + REST API.
I want users to authenticate with the app (and underlying REST API) via an OpenID Connect Provider for SSO purposes.
Using the Implicit flow I can get an ID token (JWT) identifying the user to my javascript app. I was hoping that I could then send this JWT in the Authorize header in requests to my REST API to authenticate the user. However, the problem with this approach is that the 'aud' field of the JWT won't be for the REST API server, it would be for the javascript app.
Does this mean Implicit flow is not suitable for my use case, or am I missing something?
Implicit Flow is designed for untrusted clients (such as JavaScript) to obtain identity and also (optionally) access tokens.
With OpenID Connect your authentication request must contain id_token in the response_type parameter, but it can also include token in the parameter too. See 3.2.2.1 in the spec (http://openid.net/specs/openid-connect-core-1_0.html#ImplicitAuthRequest)
e.g.
GET /authorize?
response_type=id_token%20token
&client_id=s6BhdRkqt3
&redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb
&scope=openid%20profile
&state=af0ifjsldkj
&nonce=n-0S6_WzA2Mj HTTP/1.1
Host: server.example.com
id_token means that you will get back the ID token which you have mentioned. The token means that it will also return you an access token, which is what you would use for accessing your REST api.

Resources