I am really new to Azure AD. I have read the Azure AD documentation which provides information on authentication and accessing web API's.
What I want to do : I want to use Dynamics CRM API to create a lead or contact through AWS Lambda. Meaning, whenever the Lambda function is ran, it should call the CRM API. The way I need to create a lead is with username and password creds included in Lambda. I am not sure which application scenario I need to use when I am using AWS Lambda as the source to access the web api. I want to pass the user creds with POST request.
Creating an application in Azure AD : So, I am not sure which application type I need to use (Web API or Native App?). And what should be the sign-on URL or Redirect URI?
I have tried creating an application and use Postman as the temporary way just to test whether I can get the access token and access the web api. I could able to get the access token but when I tried to access the API it says
Bearer Error invalid_token, error validating token!
I have given enough permissions while creating application in Azure AD to access Dynamics CRM API. But still unable to access the API.
POST request to get access token through Postman:
request: POST
URL: https://login.windows.net/<tenant-id>/oauth2/token
Body:
grant_type: cliet_credentials
username: xxxxx
password: xxxxxxx
client_id: <app id>
resource: <resource> //I am not sure what to include here
client_secret: <secret_key>
I get the access token in the response. Sending the second POST request using the access token
request: POST
URL: https://xxx.api.crm.dynamics.com/api/data/v8.2/accounts
Headers:
Content-type: application/json
OData-MaxVersion: 4.0
OData-Version: 4.0
Authorization: Bearer <access_token>
Body:
{
"name": "Sample Account",
"creditonhold": false,
"address1_latitude": 47.639583,
"description": "This is the description of the sample account",
"revenue": 5000000,
"accountcategorycode": 1
}
It would really help me if I can get a bit more information on where I am stuck. I have already used my one week of time to get this done. Any help will be appreciated.
To do Server-to-Server (S2S) authentication , the application is authenticated based on a service principal identified by an Azure AD Object ID value which is stored in the Dynamics 365 application user record. Please click here and here for detail steps and code samples.
Related
I have an application which consists of a frontend and several backend services. The authentication is done via Keycloak.
The workflow looks like this:
The user logs into the frontend and gets a token from Keycloak. This token is sent to the backend with every request.
The following image explains the current architecture:
In Keycloak I have the following clients:
1. Frontend
Access Type: public
Client Protocol: openid-connect
2. Core Service
Access Type: bearer-only
Client Protocol: openid-connect
3. User Service
Access Type: bearer-only
Client Protocol: openid-connect
How can I validate calls between services now?
I would imagine something like a service account and these have the possibility to call each other independently from the bearer-token from the frontend. The problem is that both services can be called from the frontend as well as between each other.
Edit:
My API is written with NestJS.
The API of the user-service:
And this is how I call the user-service in my core-service:
and this is my keycloak configuration for the the user-service:
At the moment I don't add anything to the request and I don't have any extra configuration on the interface. So I added the #Resource('user-service')-Annotation to the Controller and the #Scope()-Annotation to the Endpoint.
After that I don't get an error immediately and the endpoint is called.I can log that the logic is executed. But as response I still get a 401 Unauthorized Error.
Do I need to specify a scope or what do I need to add in the #Resource-Annotation?
Edit 2:
I'll try to show you my current situation with many screenshots.
Initial situation
Here is your drawing again. For me, points 1-5 work and point 8 works even if I do not call another service.
My Configuration
That this works, I have the following configuration:
Just Frontend and Core Service
Frontend:
Core-Service:
For the core service (gutachten-backend), I do not need to make any further configurations for this. I also have 2 different roles and I can specify them within the API.
Using Postman I send a request to the API and get the token from http://KEYCLOAK-SERVER_URL/auth/realms/REALM_NAME/protocol/openid-connect/token.
These are my 2 testing methods. I call the first one and it works. The following is logged. Means the token is validated received and I get Access:
Calling the user service
Now I call the second method. This method calls the user-service.
This is my request in the core-service:
I do not add anything else to my request. Like a bearer token in the header.
The endpoint in the user service is just a test method which logs a message.
This is my configuration for the user service:
I have now tried something with resources, policies and permissions.
Resource
Policies
Role-Policy
Client-Policy:
Permission
And analogously the client permission
Questions and thoughts
All steps from the first drawing seem to work except 6 and 7
Do I need to add more information to my request from core service to user service?
How to deal with root url and resource urls?
In the code in the API, do I need to additionally configure the endpoints and specify the specific resources and policies? (NestJS offers the possibility to provide controllers with a #Resource('<name>') and endpoints with #Scopes([<list>]))
Additionally, through a tutorial on setting up keyacloak in NestJS, I turned on the following config:
This adds a global level resource guard, which is permissive.
Only controllers annotated with #Resource and
methods with #Scopes are handled by this guard.
Keycloak's Token Verification API can do it.
This is one of Architecture for Authorization of resource access permission.
Between Core Service and User Service, Core Service needs to verify the access-token to Keycloak.
It means this token can access the User service API Yes(Allow) or No(Deny)
This is API format
curl -X POST \
http://${host}:${port}/realms/${realm}/protocol/openid-connect/token \
-H "Authorization: Bearer ${access_token}" \
--data "grant_type=urn:ietf:params:oauth:grant-type:uma-ticket" \
--data "audience={resource_server_client_id}" \
--data "permission=Resource A#Scope A" \
--data "permission=Resource B#Scope B"
Demo Keycloak Token URL: localhost:8180
Authorization Enabled Realm: test
Authorization Enabled Client: core-service
Client Resource: resource:user-service
User1 : can access it (ALLOW) password: 1234
User2 : can access it (ALLOW) password:1234
Steps
Get User Access Token(instead of login) ->
Preparations
ready to assign access-token(named user-token) variable in Postman
var jsonData = JSON.parse(responseBody);
postman.setEnvironmentVariable("user-token", jsonData.access_token);
Get Token URL from Keycloak UI, click the Endpoints
Get User1's access token
with Bearer Token option with {{user-token}} in Authorization Tab
Verify with user1 token from Core Service to Keycloak
return 200 OK from Keycloak (ALLOW) - it is Circle 4 and 5 in my Architecture.
So Core Service forward API call to User Service for accessing service
Note - needs to finish Keycloak Permission setting
Verify with user2 token from Core Service to Keycloak
return 200 OK from Keycloak (Allow) too.
So Core Service return an error to Front-end, like this user can't access a resource of User Service.
More detail information is in here
Keycloak Permission setting
Create Client
Create Client Resource
Add Client Role
Add Client Policy
Add Permission
All user mapping into Client role
This is Configuration in Keycloak
Create Client
Create Client Resource
Add Client Role
Add Client Policy - role based
Add Permission
All user mapping into Client role - any user if you want to add to access the resource.
For people who have the same problem in the future. The answer from #BenchVue helped a lot to understand the concept in general.
What was missing is that a token must also be added for each request between services. Namely the token of the client.
So before the request is sent, the following query takes place. This is the method to get the token for a client:
getAccessToken(): Observable<string> {
const header = {
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
};
return this.httpService.post(
'{{keycloakurl}}/auth/realms/{{realm}}/protocol/openid-connect/token',
`grant_type=client_credentials&client_id={{clientId}}&client_secret={{clientSecret}}`,
header).pipe(
map((response) => {
return response.data.access_token as string;
}
));
}
I am new to Google Suit. As part of a requirement, we are trying to access Google Sheets from Microsoft Flows (Power Automate) using HTTP call. I have the details to access Google Sheets API such as client_id, client_secret and redirect_uri. It would be if any thoughts on the approach to achieve the authentication with the above details.
Scenario: We have some Google Sheets which holds data to be READ and WRITE Back.
I have tried calling Google Token API with below details, but getting an error
Error 400: invalid_request
Required parameter is missing: response_type
Our main goal is to bypass user consent and authenticate Google APIs using client id and secret and perform the required actions on the data.
Steps performed to authenticate the Google API
Method: Get
URL: https://accounts.google.com/o/oauth2/auth
Headers:
{
"client_id": "xxxxxxxxxxx-xxxxx0r0e4oe1dllujkiejtm7ii42jqk.apps.googleusercontent.com",
"redirect_uri": "https://console.cloud.google.com",
"response_type": "code",
"scope": "https://www.googleapis.com/auth/spreadsheets",
"access_type": "offline",
"prompt": "none"
}
I am following https://developers.google.com/identity/protocols/oauth2/web-server#httprest as a reference.
Your formatting the request wrong. The first call is a http get you just place it in a browser window
https://accounts.google.com/o/oauth2/auth?client_id={clientid}&redirect_uri=urn:ietf:wg:oauth:2.0:oob&scope={scopes comma separated}&response_type=code
It will display the consent screen to the user. All parameters form a query string. They are not sent as headers there is nothing in the docs that says it should be sent as headers.
Useful links:
Google 3 Legged OAuth2 Flow
Understanding Google OAuth 2.0 with curl
The Discovery document
I'm trying to get list of my shared albums from Google Photos.
I found a enable Photos API in Google Developers Console.
HTTP GET:
https://content-photoslibrary.googleapis.com/v1/sharedAlbums?key=AIzaSyCkXXXXXXXXXXXXXZiOSe9IiyM8E
RESULT:
{ "error": { "code": 401, "message": "Request is missing required authentication credential. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.", "status": "UNAUTHENTICATED" } } 1
Configuration in developers console:
Please, what I'm doing wrong? Thank you.
Google API need an access token to make sure that the user has the permission to access the feature. Access token is just like cookie that should be send together with the request.
Usually you will need so many setup to get the access token with your own code. But there are a client library that can help you access Google API with small setup.
Access token also has a lifetime, so if you don't use the library you will need to manually refresh the token.
You need to configure OAUth 2.0 credentials (client ID and secret) and not an API key. More details are in the developer documentation here: https://developers.google.com/photos/library/guides/get-started#request-id
The Google Photos library API acts on behalf of a user, that's why you need to authenticate via OAuth 2.0. As part of this request you also need to specify a scope for your users to accept, see this page for more details: https://developers.google.com/photos/library/guides/authentication-authorization
I've been working on a python project to backup google photos library and album info. you can probably modify it to do exactly what you want. It is fully working but does not currently distinguish between shared and private albums.
https://github.com/gilesknap/gphotos-sync
In particular, see https://github.com/gilesknap/gphotos-sync/blob/master/gphotos/authorize.py which handles authentication and authorization for any Google service (it also handles storing the token and refreshing the token).
GET /imfpush/v1/apps HTTP/1.1
Host: mobilefoundation-3b-mf-server.mybluemix.net
Authorization: Bearer eyJhbGciOiJSUzI1NiIsImp....
Content-Type: application/json
another type of invocation
curl -X GET -H "Authorization: Bearer eyJhbGciOiJSUzI1N...." "https://mobilefoundation-3b-mf-server.mybluemix.net/imfpush/v1/apps"
Error 502: Failed to make token request, reason: Unsuccessful request to Authorization Server, server responded with status code: 400 and body : {"errorCode":"invalid_client"}, check the Authorization URL: http://localhost:8080/mfp/api/az/v1/token
TL;DR: right now looks like there is a bug in the /imfpush/v1/apps endpoint where it does not filter the applications by the vendor (APNS, GCM, WNS), so you can only get a list of all applications instead...
Note however that it all depends on your end goal. You can accomplish this by code or by using tools such as curl or Postman, Swagger etc... it all depends on what you want to achieve.
Here are 3 ways:
In the local development server - not available in Mobile Foundation service on Bluemix, you can use this URL to see the REST endpoints exposed in Swagger. You can then view push-enabled applications with this one: http://localhost:9080/doc/?url=/imfpush/v1/swagger.json#!/Applications/getAllApplications
First, in MobileFirst Operations Console > Runtime Settings > Confidential clients:
Add (just an example, choose your own) a new user client (id: user, secret: user)
Add the apps.read and push.application.* scopes
Be sure to click on the knob and add the apps.read and push.applications.* scopes.
You will also be asked to authorize. Use the username and password for the user confidential client that you previously created.
Using the /imfpush service, as described below.
Using the mfpadmin service, as described below.
In my examples I will use Postman.
In MobileFirst Operations Console > Runtime Settings > Confidential clients:
Added (just an example, choose your own) a new user client (id: user, secret: user)
Added the apps.read and push.application.* scopes
Obtained an access token by making a POST request to http://localhost:9080/mfp/api/az/v1/token with:
Authorization tab:
Type: Basic Auth
user: user
password: user
Body tab:
x-www—form-urlencoded
grant_code: client_credentials
scope: apps.read push.application.*
Obtained the list of applications by making a GET request to http://localhost:9080/imfpush/v1/apps with:
Headers tab:
Authorization: Bearer the-access-token-from-step-2
To filter the list by platform, the URL should change to the following, like the example in the API documentation: http://localhost:9080/imfpush/v1/apps/?expand=true&filter=platform==A&offset=0&size=10 But since this does not work right now... use: http://localhost:9080/imfpush/v1/apps/
Of course, you need to change localhost to your server's host.
To only obtain a list of all applications, it'd be faster to use the mfpadmin service applications endpoint. Using Postman:
Created a new GET request to http://localhost:9080/mfpadmin/management-apis/2.0/runtimes/mfp/applications
You can change the domain to yours.
In the Authorization tab, I have set the following:
Type: Basic Auth
Username and Password: your username and password (to the console)
In return I have received a list of registered applications.
I'm trying to log in and register with external authentication using MVC5, web api 2 and templates from it.
I don't know how to do it. I read
asp.net web api 2: how to login with external authentication services?.
When I call
GET /api/Account/ExternalLogins?returnUrl=%2F&generateState=true
response is
{
"Name": "Facebook",
"Url": "/api/Account/ExternalLogin?provider=Facebook&
response_type=token&
client_id=self&redirect_uri=http%3A%2F%2Flocalhost%3A6685%2F&
state=Yj1...hU1",
"State": "Yj1...hU1"
}
(I don't know what is State for)
Then i can use the Url above (authentication is with cookies) and response is OK html status and some html page (i dont know why)
This call
GET /api/Account/UserInfo
response info with null loginProvider.
I want to register user with FB or Google, so i need token, but i don't know whitch access_token and how can i get it. In example (link above) is this:
POST /api/Account/RegisterExternal
Authorization: Bearer VPcd1RQ4X... (access_token from url)
Content-Type: application/json
{"UserName":"myusername"}
but what is
access_token from url ?
So, my questions are:
How can I external register / login with web api 2 templates?
What is State for? (seems like useless)
External login is Web Api is supported out of the box and can be easily plugged in using the Owin pipeline. Gettting the access token and performing all the oauth related calls are done by the Facebook Owin Provider.
You can find a sample of facebook login with a web site here