I tried to get graph api token from postman UI and was able to get planner data.
How to achieve same in java spring
I am not able to get access token for Microsoft graph api using java spring. I am able to get access token using postman.
I need to access planner API from one of the web application. As per Microsoft documentation I configured a app in azure active directory and got client key, secret key etc.
I also configured required permission to get groups and users.
Very first time I used below from POSTMAN
https://login.microsoftonline.com//oauth2/token with below data
client_id : <client_id from configured app>
client_secret : <client secret from configured app>
grant_type : client_credentials
resource : https://graph.microsoft.com
I got token, and I was able to get groups from https://graph.microsoft.com/v1.0/groups/
But same token was not valid for getting plans of group.
With lot of digging, I came to know that token accessed with client_credentials is not applicable to get data from planner API. So, next I used below details to get access token from UI of postman.
Grant Type : authorization_code
Callback URL : https://www.getpostman.com/oauth2/callback
Auth URL : https://login.microsoftonline.com/<tenant_id>/oauth2/authorize?resource=https://graph.microsoft.com
Access Token URL : https://login.microsoftonline.com/<tenant_id>/oauth2/v2.0/token
client_id : <client_id from configured app>
client_secret : <client secret from configured app>
I got the Microsoft login screen, and after successful login, I got token.
I could call planner API using this access token.
Now my question is how can I get this same token using java spring.
Also, my web app will be having background service running in scheduler calling graph API daily.
I do not want manual intervention here, but as told earlier, graph API will ask to login.
How to achieve above requirement.
private String getAuth() {
ConfidentialClientApplication app = null;
IClientCredential credential = ClientCredentialFactory.create(Appsecret);
try {
app = ConfidentialClientApplication.builder(MicrsoftAppId, credential).authority("https://login.microsoftonline.com/"+tenantId+"/").build();
}catch(MalformedURLException e) {
System.out.println(e.getMessage());
}
ClientCredentialParameters parameters = ClientCredentialParameters.builder(Collections.singleton("https://graph.microsoft.com/.default")).build();
CompletableFuture<IAuthenticationResult> future = app.acquireToken(parameters);
try {
IAuthenticationResult result = future.get();
return result.accessToken();
}catch(ExecutionException e){
System.out.println(e.getMessage());
}catch(InterruptedException e) {
System.out.println(e.getMessage());
}
return null;
}
Here you go! This code is made for application permission (so not delegated). It only requires your client Id and secret to operate. You will need the microsoft graph jar for it to work (and the many jars supporting it).
Related
I've recently faced a problem.
My frontend use Oauth2 to authenticate my user on Azure (Organization). This giives me multiple information containing idToken and accessToken.
My Backend uses AADResourceServerWebSecurityConfigurerAdapter to authenticate the user thanks to the idToken put in the Authorization Bearer header from the frontend.
Unitil here everything works well. I can get the connected user with this:
public static String getConnectedUserEmail() {
return (String) ((AADOAuth2AuthenticatedPrincipal) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getAttributes().get("preferred_username");
}
I use my backend app credentials to contact the graph api on behalf of the API itself.
Though, following Azure Ad documentation, I cannot query group/calendar on behalf of the API, I have to do it on behalf of the user.
To respect SOLID principles, I want to make the request from the backend, but on behalf of the user.
I cannot find any information about that.
So here is my final question: How can I make a graph API request in my backend on the behalf of the user?
Knowing that trying to use the tokenValue (idToken) of the user or the accessToken value returns invalid credentials from Microsoft.
You requested GET /groups/{id}/calendar to get group calendar as you said.
You can call Graph API with the access token using on-behalf-of flow, see here.
There is a sample using the On-Behalf-Of flow: https://github.com/Azure-Samples/ms-identity-java-webapi
Note: Make sure the following delegated permission is added.
I have been given a spring boot web api project. There is a flutter application that will send a jwt token as a request and the api has to get the "ticket" value out of the payload and then check the database and send the required data. I am totally a newbie in this field but I have no choice rather than complete it.
I wanted to make the matter easy by just accepting the token and try to decode that and get the "ticket" value out. But I was unable to do so as I am unable to get the token in the very first place.
The authentication is being done by some other api and that is providing the jwt token to the flutter application. Then the flutter application will send that token in any request to my api. I have a sample database with the data required and will have to resolve the request using "ticket" (which is acting as a username) from the database and will provide the data. I don't have to perform any authentication part - I just have to extract the token from the request - decode that and get the "ticket" value and have to search the database and provide the data.
token : eyJhbGciOiJIUzUxMiJ9.eyJ0aWNrZXQiOiJzdmxhZGFAZ21haWwuY29tIiwic2NvcGVzIjpbIlJPTEVfQURNSU4iLCJST0xFX1BSRU1JVU1fTUVNQkVSIl0sImlzcyI6Imh0dHA6Ly9zdmxhZGEuY29tIiwiaWF0IjoxNDcyMzkwMDY1LCJleHAiOjE0NzIzOTA5NjV9.uaHqDrTNnn5TAljcWRYac9ifJJv5NR5cdn7id2xVCAKLD37_pY62jPlk70XtwqgSar03n2qEgzWyTdWXRcnsgQ
reuest : localhost:8080/persons?access_token=eyJhbGciOiJIUzUxMiJ9.eyJ0aWNrZXQiOiJzdmxhZGFAZ21haWwuY29tIiwic2NvcGVzIjpbIlJPTEVfQURNSU4iLCJST0xFX1BSRU1JVU1fTUVNQkVSIl0sImlzcyI6Imh0dHA6Ly9zdmxhZGEuY29tIiwiaWF0IjoxNDcyMzkwMDY1LCJleHAiOjE0NzIzOTA5NjV9.uaHqDrTNnn5TAljcWRYac9ifJJv5NR5cdn7id2xVCAKLD37_pY62jPlk70XtwqgSar03n2qEgzWyTdWXRcnsgQ
The code is not necessary I just want to learn how it works. There are many videos in YouTube but they all are concentrated on the authentication which I don't have to perform and none is showing how the request from the application is to be handled. Any resources will also be a great help. Thank You.
reuest : localhost:8080/persons?access_token=eyJhbGciOiJIUzUxMiJ9.eyJ0aWNrZXQiOiJzdmxhZGFAZ21haWwuY29tIiwic2NvcGVzIjpbIlJPTEVfQURNSU4iLCJST0xFX1BSRU1JVU1fTUVNQkVSIl0sImlzcyI6Imh0dHA6Ly9zdmxhZGEuY29tIiwiaWF0IjoxNDcyMzkwMDY1LCJleHAiOjE0NzIzOTA5NjV9.uaHqDrTNnn5TAljcWRYac9ifJJv5NR5cdn7id2xVCAKLD37_pY62jPlk70XtwqgSar03n2qEgzWyTdWXRcnsgQ
From the above request, you can design the controller like as follows :
#GetMapping("/persons")
public ResponseEntity loadPersons(#RequestParam("access_token") String access_token,HttpServletRequest request){
//Here you can play with the token now
//you can also get the token if it is coming with request header as follows :
String token =request.getHeader("access_token");//replace with the specific key
}
e.g.
public boolean isValidJWTToken(String jwtToken){
boolean isValid = true;
try {
Jwts.parser().setSigningKey(generateKey()).parseClaimsJws(jwtToken);
} catch (Exception e) {
isValid = false;
}
return isValid;
}
private Key generateKey() {
byte[] keyBytes=environment.getProperty("auth.jwt.secret.key").getBytes();
return new SecretKeySpec(keyBytes, 0,keyBytes.length,environment.getProperty("auth.jwt.secret.algo"));
}
TheJWT Token has 3 parts .
1. HEADER:ALGORITHM & TOKEN TYPE
2. PAYLOAD:DATA
3. SIGNATURE
All the above 3 parts are your business driven. So you can better know which is the algo used for encode . Accordingly, you can do decode.
I am running the official SDK Junit codes, and it works fine. But when I change the account info into mine, exception occur.
Debug says it return http status of 400 when posting to endpoint "/oauth/token",
I have save my private key generated in docusign admin page, into "docusign_private_key.txt"
ApiClient apiClient = new ApiClient (BaseUrl);
//String currentDir = System.getProperty("user.dir");
try
{
// IMPORTANT NOTE:
// the first time you ask for a JWT access token, you should grant access by making the following call
// get DocuSign OAuth authorization url:
//String oauthLoginUrl = apiClient.getJWTUri(IntegratorKey, RedirectURI, OAuthBaseUrl);
// open DocuSign OAuth authorization url in the browser, login and grant access
//Desktop.getDesktop().browse(URI.create(oauthLoginUrl));
// END OF NOTE
byte[] privateKeyBytes = null;
try
{
privateKeyBytes = Files.readAllBytes (Paths.get (privateKeyFullPath) );
}
catch (IOException ioExcp)
{
Assert.assertEquals (null, ioExcp);
}
if (privateKeyBytes == null)
{
return;
}
java.util.List<String> scopes = new ArrayList<String>();
scopes.add (OAuth.Scope_SIGNATURE);
scopes.add (OAuth.Scope_IMPERSONATION);
OAuth.OAuthToken oAuthToken = apiClient.requestJWTUserToken (IntegratorKey, UserId, scopes, privateKeyBytes, 3600);
}
Problem solved.
The SDK JUnit code defines a parameter called "UserId", it should be filled by "API Username" , not "API Account ID" from Admin page.
Thanks for all you kind people.
Per the note in the comments, you need to grant one-time user consent per key for your app to use it, have you done that? If you have Organizations enabled (which is an enterprise feature) then you can do it across the entire account, otherwise you'll need to grant consent manually on a one-by-one (ie user by user) basis.
If granting consent manually (which is what most integrations do) you need to configure your Integrator Key with the Redirect URI you will be passing through code, then redirect your user to the following URL in a web browser (the "-d" part of the URL means this would be for the demo environment):
https://account-d.docusign.com/oauth/auth?
response_type=YOUR_RESPONSE_TYPE
&scope=open_id
&client_id=YOUR_INTEGRATOR_KEY
&state=YOUR_CUSTOM_STATE
&redirect_uri=YOUR_REDIRECT_URI
&admin_consent_scope=YOUR_REQUESTED_SCOPES
If done correctly the user will be taken to the standard DocuSign login page. After successful login they can explicitly grant consent to your app and will then be re-directed back to your app through the Redirect URI param you configured.
Here is a guide that explains how to obtain consent using either method:
https://developers.docusign.com/esign-rest-api/guides/authentication/obtaining-consent
I've been experimenting with Azure Active Directory access for Java using two sample projects:
1) https://github.com/AzureAD/azure-activedirectory-library-for-java which builds a stand-alone war using OAuth tokens for security, and
2) https://github.com/Microsoft/azure-spring-boot/tree/master/azure-spring-boot-samples/azure-active-directory-spring-boot-backend-sample for spring-boot embeded containers
I've come across quite a difference in the way the APIs can be used, that I can't understand.
In both cases, I get an OAuth token for AD by logging in with my Azure credentials.
In the Http response, I get an authorizationCode of the form:
AQABAAIAAAD.....
Then using the following URL as an authContext:
https://login.microsoftonline.com/{tenantId}
I get a AuthenticationResult by making the following call:
Future<AuthenticationResult> future = authContext.acquireTokenByAuthorizationCode(authorizationCode, redirectUri, credential, null);
in the Adal4j project (1), the AuthenticationResult's AccessToken is of the form:
eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6I...
Which I can use as a Bearer token in an HTTP call to retrieve the user's profile picture via https://graph.windows.net/myorganization/me/thumbnailPhoto?api-version=1.6
whereas in the SpringBoot AD example, the AccessToken returned from exactly the same call is of the form:
AQABAAAAAADXzZ3ifr-GRbDT....
and If I use that in exactly the same way to try to retrieve the user's profile pic, I get a 401 Unauthorized response
What's the reason for the difference in the form and use of these AccessTokens?
What's the reason for the difference in the form and use of these AccessTokens?
I assume that you got the access token is authorization_code not the bearer token.
As Rohit Saigal mentioned that you could use JWT.IO or JWT.MS to check that.
If we want to get the access token for Azure AD graph we could use the follow code to do that.
public String index(Model model, OAuth2AuthenticationToken authentication) {
...
DefaultOidcUser user = (DefaultOidcUser)authentication.getPrincipal();
String accessToken = user.getIdToken().getTokenValue();
...
}
Then we could use the access token to access the Azure AD graph api if you have assiged corrosponding permission.
How can I authenticate programmatically to Google?
Now that ClientLogin (https://developers.google.com/accounts/docs/AuthForInstalledApps)
is deprecated, how can we perform a programmatic authentication to Google with OAuth2?
With ClientLogin we could perform a post to
https://www.google.com/accounts/ClientLogin
with email and password parameters and obtain the authentication token.
With OAuth2 i can't find a solution!
#
My app is a java background process.
I saw, following this link: developers.google.com/accounts/docs/OAuth2InstalledApp#refresh, how to obtain a new access token using a refreshed token.
The problem is that I can't find a java example about how to instantiate an Analytics object (for example) to perform a query when I have a new valid access token
This is my code that returns a 401 Invalid credentials when invoke the "execute()":
public class Test {
static final String client_id = "MY_CLIENT_ID";
static final String client_secret = "MY_SECRET";
static final String appName = "MY_APP";
private static final HttpTransport HTTP_TRANSPORT = new NetHttpTransport();
private static final JsonFactory JSON_FACTORY = new JacksonFactory();
static String access_token = "xxxx";
static String refreshToken = "yyyyy";
public static void main (String args[]){
try {
GoogleCredential credential =
new GoogleCredential.Builder()
.setTransport(HTTP_TRANSPORT)
.setJsonFactory(JSON_FACTORY)
.setClientSecrets(client_id, client_secret).build();
credential.setAccessToken(access_token);
credential.setRefreshToken(refreshToken);
//GoogleCredential
Analytics analytics = Analytics.builder(HTTP_TRANSPORT, JSON_FACTORY)
.setApplicationName(appName)
.setHttpRequestInitializer(credential)
.build();
Accounts accounts = analytics.management().accounts().list().execute();
} catch (Exception e) {
e.printStackTrace();
}
}
What is the problem?
Check the OAuth 2 flow for Installed Application:
https://developers.google.com/accounts/docs/OAuth2InstalledApp
It still requires the user to authenticate with a browser the first time, but then you can store the refresh token and use it for subsequent requests.
For alternative solutions, check the Device flow or Service Accounts, they are explained in the same documentation set.
I found the Google Java client to be overly complex and poorly documented. Here's plain and simple Servlet example with Google Oauth2. For a background process you'll need to request access_type=offline. As others have mentioned you need the user to do a one time authorization. After that you can request refresh tokens as google tokens expire in an hour.
Although I appreciate that the OP was originally targeting the OAuth2InstalledApp approach, I would like to point out a working solution using the OAuth2WebServer approach. They don't differ significantly and this worked for me. I have found the google OAuth library to be pretty good as it will handle most of the OAuth dance for you and it makes it easy to refresh the access token. The solution below depends on using a pre-obtained refresh token.
As the accepted answer states, to get OAuth authentication working (even for a Java background process) where the request relies upon access to user data
requires the user to authenticate with a browser the first time, but then you can store the refresh token and use it for subsequent requests.
From previous comments by the OP I see the following
So I followed OAuth2 for Web Server Applications (here offline access is documented) but I have still problems.
1) I perform the first request via browser and I obtain autenticaton code for offline access
2) I perform a java post of the authentication code and obtain acces token and refresh token
The approach I used is more like
1) I perform the first request via a browser and obtain the refresh token for offline access
2) In java I provide the refresh token to the library and the library will obtain the access token etc
specifically, using the google-api-java-client library the code is quite straightforward and note that I haven't set an access token as the OP did, as I am calling credential.refreshToken(); elsewhere. (I check if I have a valid access token already and if not call refresh prior to the API call)
private Credential generateCredentialWithUserApprovedToken() throws IOException,
GeneralSecurityException {
JsonFactory jsonFactory = JacksonFactory.getDefaultInstance();
HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
InputStreamReader inputStreamReader =
new InputStreamReader(jsonFileResourceForClient.getInputStream());
GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(jsonFactory, inputStreamReader);
return new GoogleCredential.Builder().setTransport(httpTransport).setJsonFactory(jsonFactory)
.setClientSecrets(clientSecrets).build().setRefreshToken(REFRESH_TOKEN);
}
Note this covers step 2 of my approach, and the REFRESH_TOKEN mentioned in step 1 can be obtained as explained below.
First there is a prior set up of a web app creating an OAuth 2.0 client ID on the Google console for Credentials where you end up with a downloaded json file which will be read into the GoogleClientSecrets object.
i.e.
Make sure you add the Google playground callback uri into Authorized redirect URIs
Then you have your client id and the client secret ready for the playground and you can also download the json which you can pull into your Java code.
The REFRESH_TOKEN is obtained by sending a request to the google oauth playground with the following configuration. Note that prior to Step 1 and selecting your scope you should go to settings to check that you are providing you own credentials and add your client id and secret just below that
Note that the Access type is Offline, which corresponds to this.
There is also a nice explanation on grabbing the refresh token here https://www.youtube.com/watch?v=hfWe1gPCnzc
That is enough to get going and is a one time set up!
Regarding refresh tokens you should be aware of their lifecycle as discussed in the docs here
In the oauthplayground you will see this
but on point 4 of the docs here it says this
Hmmm.
Also for reference see How do I authorise an app (web or installed) without user intervention? (canonical ?)
For applications that authenticate on behalf of themselves (i.e., to another application, traditionally by signing into a role account using a shared password), the OAuth2 alternative to ClientLogin offered by Google is Service Accounts:
https://developers.google.com/accounts/docs/OAuth2ServiceAccount