How do I revoke access that has been granted to my Google Drive web application so that upon the user's next use he is asked for permissions afresh?
For revoking your access token, you need to "GET" (!) this url:
https://accounts.google.com/o/oauth2/revoke?token={token}
where {token} is the value of your token, as explained here:
https://developers.google.com/accounts/docs/OAuth2WebServer#tokenrevoke
For Java API (don't know for other languages), as of 9th of Sept 2012, there is no API for this.
I managed to revoke a token with this code:
class myGoogleApi {
private static final HttpTransport HTTP_TRANSPORT = new NetHttpTransport();
...
public revoke(String token) {
HttpRequestFactory factory = HTTP_TRANSPORT.createRequestFactory();
GoogleUrl url = new GoogleUrl("https://accounts.google.com/o/oauth2/revoke?token="+token);
HttpRequest request = factory.buildGetRequest(url);
HttpResponse response = request.execute();
...
}
If you clobbered all the refresh tokens in your DB, adding the query parameter approval_prompt=force to the auth request will fix that. It'll result in the refresh tokens getting reissued when the user next approves the request.
In order to revoke the access go to the below url
https://security.google.com/settings/security/permissions?pli=1
Choose your apps that you need to revoke and click on remove.
Visit https://accounts.google.com/b/0/IssuedAuthSubTokens?hl=en for the list of applications and sites that you granted access to. Next to each of them you'll find a Revoke Access button.
The instructions to get to that page are at http://support.google.com/accounts/bin/answer.py?hl=en&answer=41236
Using Google Play Services:
http://developer.android.com/reference/com/google/android/gms/auth/GoogleAuthUtil.html
Add https://www.googleapis.com/auth/userinfo.profile to your scope.
Example:
String scope="oauth2:https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile"
final String token = GoogleAuthUtil.getToken(context, "xxxx#gmail.com", scope);
OR "brute force"
Intent res = new Intent();
res.addCategory("account:xxxx#gmail.com");
res.addCategory("scope:oauth2:https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile");
res.putExtra("service", "oauth2:https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile");
Bundle extra= new Bundle();
extra.putString("androidPackageName","com.your.package");
res.putExtra("callerExtras",extra);
res.putExtra("androidPackageName","com.your.package");
res.putExtra("authAccount","xxxx#gmail.com");
String mPackage = "com.google.android.gms";
String mClass = "com.google.android.gms.auth.TokenActivity";
res.setComponent(new ComponentName(mPackage,mClass));
startActivityForResult(res,100);
Now, when you revoke the access here https://accounts.google.com/IssuedAuthSubTokens the application shows you the window for permission again in the device.
Related
I want to get access token to get access to Outlook by IMAP using MSAL.
The code used to get the access token is below(written by Kotlin).
fun getAccessTokenByMSAL(
appId: String,
scopes: List<String>
): String? {
val scopeSet = HashSet<String>()
scopes.stream().forEach { scope ->
scopeSet.add(scope)
}
val app = PublicClientApplication
.builder(appId)
.authority("https://login.microsoftonline.com/common")
.build();
val params = InteractiveRequestParameters
.builder(URI("http://localhost:8080"))
.scopes(scopeSet)
.build()
val result = app.acquireToken(params).join()
return result.accessToken()
}
To get access to Outlook by IMAP, I want to add "IMAP.AccessAsUser.All" permission as scope like below.
val scopes = listOf(
"https://outlook.office365.com/IMAP.AccessAsUser.All",
)
val token = getAccessTokenByMSAL(appId, scopes)
However, as a result, when I try to log in with my personal account, I get the following error message in my browser (The error message has no embedded character string and is displayed strangely.):
Authentication failed. You can return to the application. Feel free to close this browser tab.
Error details: error {0} error_description: {1}
When I change scope as follows and try again, then authentication success.
val scopes = listOf(
"IMAP.AccessAsUser.All"
)
val token = getAccessTokenByMSAL(appId, scopes)
So, what are the difference between scope "IMAP.AccessAsUser.All" and "https://outlook.office365.com/IMAP.AccessAsUser.All"?
And which is correct to get right access token to connect Outlook by IMAP?
It's a mess.
IMAP.AccessAsUser.All
E.g.,
https://graph.microsoft.com/IMAP.AccessAsUser.All
Is a Microsoft Graph audience scope, but it seems its completely useless client-side, and is only used when adding scopes to your app.
On the other hand,
https://outlook.office365.com/IMAP.AccessAsUser.All
Is the scope you have to request client-side, if you want to access Exchange mailboxes using IMAP with OAuth 2.0.
You can't add it to your application scopes, but if you add:
https://graph.microsoft.com/IMAP.AccessAsUser.All
It allows you to request both of the following:
https://graph.microsoft.com/IMAP.AccessAsUser.All https://outlook.office365.com/IMAP.AccessAsUser.All
I'm talking from my experience trying to access Exchange Enterprise (in-tenant) mailboxes via IMAP with OAuth 2.0. It could be different for personal and school accounts.
I have a Web API and a UI application that used ADAL library to call the Web API.
I already gave DELEGATED PERMISSIONS (Read directory data) for both Web API and UI application while registering the apps to Azure AD.
I have below code in Web API to save Token for log-In user,
private void ConfigureAuthentication(IAppBuilder app)
{
app.UseWindowsAzureActiveDirectoryBearerAuthentication(
new WindowsAzureActiveDirectoryBearerAuthenticationOptions
{
Tenant = ConfigurationManager.AppSettings["ida:Tenant"],
TokenValidationParameters = new TokenValidationParameters { SaveSigninToken = true, ValidAudience = ConfigurationManager.AppSettings["ida:Audience"] }
});
}
Now in Web API controllers, I am trying to get token to access Microsoft AD Graph API using below code,
var bootstrapContext = ClaimsPrincipal.Current.Identities.First().BootstrapContext as System.IdentityModel.Tokens.BootstrapContext;
string userName = "test#onmicrosoft.com";
string userAccessToken = bootstrapContext.Token;
UserAssertion userAssertion = new UserAssertion(bootstrapContext.Token, "urn:ietf:params:oauth:grant-type:jwt-bearer", userName);
var authContext = new AuthenticationContext(string.Format(CultureInfo.InvariantCulture, aadInstance, tenant));
var clientCred = new ClientCredential(clientId, appKey);
var result = await authContext.AcquireTokenAsync("https://graph.windows.net", clientCred, userAssertion);
accessToken = result.AccessToken;
The above code giving me token back but the scope values is below,
`scp: "User.Read"`
Question - Why the token not giving directory access (Directory.Read.All) as I already set Directory access?
`scp: "Directory.Read.All User.Read"`
Update:
I am missing Grant Permission for Read Directory Data under DELEGATED PERMISSIONS. After giving Grant Permission I am able to get token with scope scp: "Directory.Read.All User.Read"
If I understand correctly, you want to use Microsoft Graph API ,not Azure AD Graph API.
However, based on that the screenshot you post in this question is a v1 enpoint AAD Application, it does nothing about Microsoft Graph API which you're trying to approaching. So, whatever you changed on this application, the result shouldn be same. I suggest you register v2 enpoint Application in https://apps.dev.microsoft.com/
Here is a document which shows how to get auth tokens for using Microsoft Graph.
Hope this helps!
I'm trying to pull google contacts information (photos, gender and more) and we used Google People API to do that.
I use in createContact service to search contact by an Email.
I created a client id and client secret, and with the simple code of oAuth2.0, I got a refresh token that my server used to generate credentials.
HttpTransport httpTransport = new NetHttpTransport();
JacksonFactory jsonFactory = new JacksonFactory();
String clientId = "";
String clientSecret = "";
String scope = "https://www.googleapis.com/auth/contacts";
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
httpTransport, jsonFactory, clientId, clientSecret,
Arrays.asList(scope))
.setAccessType("offline")
.setApprovalPrompt("force")
.build();
LocalServerReceiver localReceiver = new LocalServerReceiver.Builder().setPort(8089).build();
Credential credential = new AuthorizationCodeInstalledApp(flow, localReceiver).authorize("user");
In that way, I get the refreshToken and save it offline in a secured file.
After that, my application connect to google and get the clientId, ClientToken, and RefreshToken from that file and try to connect -
GoogleCredential googleCredential = new GoogleCredential.Builder()
.setJsonFactory(jsonFactory)
.setTransport(transport)
.setClientSecrets(googlePeopleKey.getClientId(), googlePeopleKey.getClientSecret())
.build().setRefreshToken(googlePeopleKey.getRefreshToken());
It seems that the result is different per user. When I operate with a refresh code that my user authenticate earlier, I can't get all the information that another user in my company (that authorized by the same way) does. Today, it flipped, and in another test, I get results that he didn't. Very strange.
I was looking up about limit rate but, it seems that I even not near the limitations.
Do you have any idea why it returns different result for different users? The different result means that sometimes one of the users can see the profile picture but the other one can't.
Thank you!
I have developed a Azure API protected with AAD , which is working fine,
now I would like to call SharePoint online REST API from my Azure API ,my SharePoint online is using same active directory as my azure API.
For calling SP API i need access token to authenticate SharePoint
I assume the access token which authenticated the Azure API would be same to call SharePoint API
this is what I did :
My Azure API is registered in azure active directory (which is automatically done which I made authentication on )
I updated the Azure app's manifest.json to enable oauth2 implicit flow:
"oauth2AllowImplicitFlow": true
I granted the app access to "Read and write items and lists in all site collections" on behalf of the user (under delegated permissions) from the Azure AD app settings page ("permissions to other applications").
I tried to this code to get access token :
string clientId = "xxxxxxxxxx";
string appKey = xxxxxxxxxxx";
string aadInstance = "https://login.microsoftonline.com";
string tenant = "mydomain.onmicrosoft.com";
string domain = "mydomain.onmicrosoft.com";
string resource = "https://mydomain.sharepoint.com";
AuthenticationResult result = null;
ClientCredential clientCred = new ClientCredential(clientId, appKey);
string authHeader = HttpContext.Current.Request.Headers["Authorization"];
string userAccessToken = authHeader.Substring(authHeader.LastIndexOf(' ')).Trim();
UserAssertion userAssertion = new UserAssertion(userAccessToken);
string authority = aadInstance + domain;
AuthenticationContext authContext = new AuthenticationContext(authority);
//result = await authContext.AcquireTokenAsync(resource, clientCred); // auth without user assertion (fails, app only not allowed)
result = await authContext.AcquireTokenAsync(resource, clientCred, userAssertion); // clientCred and userAssertion params have swapped places since Kirk's blog
return result.AccessToken;
but authHeader is null ,
I came across this question which mentions in order to retrieve a user token uses ADAL.js using authenticationContext.acquireToken(clientId), then include the resulting token in the header of the AJAX request to the WebAPI
I am not sure how i need to include this in my azure API
anyway i appreciate any thoughts or idea to get access token to run SharePoint online APIs behalf of logged in user in azure API
I'm going to implement OAuth 2.0 and REST API with it
to grant different permissions per users and also to scale well.
To scale well, stateless is easier because there is
NO file, database, in-memory based session with it.
Below is how I understand OAuth 2.
OAuth Server give an access token to a user.
The user's access token is stored in cookie.
When user access to REST API, user sends with the access token.
Server receives request with access token.
Server find out whether access token is valid and the user has permission to do request.
Do or reject based on user's privilege.
So I do not have to worry about session storage. Right?
What you are describing here, is the OAuth 2 Implicit Grant flow. OAuth 2 also includes three other flows, but as it seems that your ressource owner (the user) is initiating requests using browser side Javascript (you were talking about cookies), this is the flow you should go for.
On client side, OAuth only requires you to store the access_token for accessing protected ressources (and a refresh_token if you're going for an expiring access_token).
A more recent innovation is JWT - JSON Web Token.
Here is a link to the spec:
JWT - JSON Web Token
JWT is a method of using Hashed tokens using a Hashing method such as HMAC which stands for a Hash-based Message Authentication Code. Because the token is hashed using a secret key, the server can determine if the token has been tampered with.
Here is an example method to create a Hashed token for JWT:
public String createTokenForUser(User user) {
byte[] userBytes = toJSON(user);
byte[] hash = createHmac(userBytes);
final StringBuilder sb = new StringBuilder(170);
sb.append(toBase64(userBytes));
sb.append(SEPARATOR);
sb.append(toBase64(hash));
return sb.toString();
}
Here is an example of decoding a token to ensure it was not tampered with:
public User parseUserFromToken(String token) {
final String[] parts = token.split(SEPARATOR_SPLITTER);
if (parts.length == 2 && parts[0].length() > 0 && parts[1].length() > 0) {
try {
final byte[] userBytes = fromBase64(parts[0]);
final byte[] hash = fromBase64(parts[1]);
boolean validHash = Arrays.equals(createHmac(userBytes), hash);
if (validHash) {
final User user = fromJSON(userBytes);
if (new Date().getTime() < user.getExpires()) {
return user;
}
}
} catch (IllegalArgumentException e) {
//log tampering attempt here
}
}
return null;
}
Here is an article with a more complete example: Stateless Authentication