I have created an azure application using the Microsoft azure platform.
using the below script I make an attempt to connect to the API using the credentials given when creating the azure application.
from O365 import Account
credentials = ('azureApp_clientId', 'azureApp_clientSecret')
account = Account(credentials)
if account.authenticate(scopes=['Mail.Read']):
print('Authenticated!')
When the script runs it returns a URL to add to a browser and give consent..
https://login.microsoftonline.com/common/oauth2/v2.0/authorize?xxxxxxxxxx
When i paste the URL into my browser it does nothing and returns a blank page..
This is my redirect URI in the azure app
What am I missing??
Docs to o365 Lib here https://pypi.org/project/O365/
Update
from O365 import Account
credentials = ('myclientID')
account = Account(credentials, auth_flow_type = 'public')
if account.authenticate(scopes = ['Mail.Read']):
print('Authenticated!')
mailbox = account.mailbox()
inbox = mailbox.inbox_folder()
for message in inbox.get_messages():
print(message)
Update
According to the configuration of the application azure (you register the application as Mobile and desktop applications), you should use the method Authenticate on behalf of a user (public) to do auth and should not provide client_secret. For more details, please refer to here and here.
For example
from O365 import Account
credentials = ('<your client_id>',)
account = Account(credentials,auth_flow_type='public')
if account.authenticate(scopes==['Mail.Read'] ):
print('Authenticated!')
mailbox = account.mailbox()
inbox = mailbox.inbox_folder()
for message in inbox.get_messages():
print(message)
#Update
My configuration
Related
I am trying to create a user in Google Admin via API
(google admin)
Things I have done:
create service account and credentials
installed sdk lib
read multiple docs on service account/Oauth credentials, google sdk authen., admin api
code
class Gcp:
def __init__(self):
SERVICE_ACCOUNT_FILE = "core/gcp/XXX.json"
read_domain_scope = 'https://www.googleapis.com/auth/admin.directory.domain.readonly'
admin_user_scope = 'https://www.googleapis.com/auth/admin.directory.user'
read_ou_scope = 'https://www.googleapis.com/auth/admin.directory.orgunit.readonly'
SCOPES = [read_domain_scope, admin_user_scope, read_ou_scope,]
self.credential = service_account.Credentials.from_service_account_file(SERVICE_ACCOUNT_FILE, scopes=SCOPES)
def list_user(self):
res = googleapiclient.discovery.build('users', 'v1', credentials=self.credential)
return 'OK'
Problems:
I can not find a document which specify how I can create user in google admin via SDK, I mean I've found the REST api doc
But I seems that I need to authenticate through OAuth2 for the REST calls.
Is there a way to get this (create user and assign domain/organization unit) done with just service account credential file with SDK?
I write a python script to upload file to google drive, but the script is redirecting to chrome for email user authentication.
is there any way to avoid redirecting to chrome for authentication.
I'm running on python 3.9.
here is my sample code:
from pydrive.auth import GoogleAuth
from pydrive.drive import GoogleDrive
gauth = GoogleAuth()
drive = GoogleDrive(gauth)
upload_file_list = ['myfile.pdf']
for upload_file in upload_file_list:
gfile = drive.CreateFile({'parents': [{'id': '1B8ttlQMRUkjbrscevfa1DablIayzObh2'}]})
# Read file and set it as the content of this instance.
gfile.SetContentFile(upload_file)
gfile.Upload() # Upload the file.
The behaviour you are reporting is totally normal with OAuth 2.0 and the official Google APIs library.
What #Tanaike said is a good solution. You could use a service account to access Google Drive files without granting consent every time the token expires. With service accounts there are 2 options to achieve that:
Share the file/folder with the email address of the service account.
Use domain-wide delegation of authority to allow the service account to impersonate any user in your domain. Requires a domain using Google Workspace or Cloud Identity and Super Admin access to configure domain-wide delegation.
General information on how to make API calls with domain-wide delegation is available on this page https://developers.google.com/identity/protocols/oauth2/service-account#authorizingrequests.
Here is a working code sample:
from google.oauth2 import service_account
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
# Scopes required by this endpoint
# https://developers.google.com/drive/api/v3/reference/permissions/list
SCOPES = ["https://www.googleapis.com/auth/drive.readonly"]
# Variable that holds the file ID
DOCUMENT_ID = "i0321LSy8mmkx_Bw-XlDyzQ_b3Ny9m74u"
# Service account Credential file downloaded with domain-wide delegation of authority
# or with shared access to the file.
SERVICE_ACCOUNT_FILE = "serviceaccount.json";
# Creation of the credentials
credentials = service_account.Credentials.from_service_account_file(
SERVICE_ACCOUNT_FILE,
scopes=SCOPES)
# [Impersonation] the service account will take action on behalf of the user,
# requires domain-wide delegation of authority.
delegated_credentials = credentials.with_subject('user#domain.com')
# The API call is attempted
try:
service = build('drive', 'v3', credentials=delegated_credentials)
# Retrieve the documents contents from the Docs service.
document = service.files().get(fileId=DOCUMENT_ID).execute()
print('The title of the document is: {}'.format(document.get('name')))
except HttpError as err:
print(err)
Keep in mind that to use user impersonation you will need to configure domain-wide delegation in the Admin console of the domain that has the files (this will also work for external files shared with users in the domain).
If you want to use this with regular consumer accounts you can't use user impersonation, instead you will share the file with the service account (read or write access) to later make API calls. Line 20 creates delegated credentials, this line needs to be removed if you will use this other approach.
I have a Python code that was using SendGrid API to send emails, but now I want to migrate to Google in order to send business emails. It also runs in Docker containers.
I followed Gmail Python Quickstart in order to use Gmail API in my Python code and the problem is that when trying to send email, it shows an authorization link in Docker logs in order to get token, etc.
Is there a way to complete authorization in the background without any further interaction or use an API key just like SendGrid to programmatically authenticate your application?
I am a service provider and want to send emails such as reset password links, confirmation code, etc. automatically; the code is deployed on a Linux host. I have access to workspace account, and I already have verified my domain.
The tutorial you are following is designed for an installed application. Hence the InstalledAppFlow.
It states it at the top of the file.
Authorization credentials for a desktop application. To learn how to create credentials for a desktop application, refer to Create credentials.
This means when your code runs it is going to pop up the consent screen on the machine the code is running on, in this instance Docker.
flow = InstalledAppFlow.from_client_secrets_file(
'credentials.json', SCOPES)
You need to create it using a web application so that your users can consent to your application accessing their data and their Gmail account.
Automated send emails service account option.
You were not clear as who you are sending emails for. As you are using send grid, it implies to me this is some kind of automated system. Which would mean that you are trying to send emails on behalf of a Gmail account that you control.
In that case you would most often want to use a service account. Service accounts allow for server-to-server interaction between Google APIs. However, service accounts will only work with Gmail if this is a Google workspace Gmail account and you can set up domain-wide delegation.
There is an example in the documentation. Just change it to Gmail scopes. The key point is the create_delegated which must be a user on your domain.
from googleapiclient.discovery import build
from oauth2client.service_account import ServiceAccountCredentials
# Email of the Service Account
SERVICE_ACCOUNT_EMAIL = '<some-id>#developer.gserviceaccount.com'
# Path to the Service Account's Private Key file
SERVICE_ACCOUNT_PKCS12_FILE_PATH = '/path/to/<public_key_fingerprint>-privatekey.p12'
def create_directory_service(user_email):
"""Build and returns an Admin SDK Directory service object authorized with the service accounts
that act on behalf of the given user.
Arguments:
user_email: The email of the user. Needs permissions to access the Admin APIs.
Returns:
Admin SDK directory service object.
"""
credentials = ServiceAccountCredentials.from_p12_keyfile(
SERVICE_ACCOUNT_EMAIL,
SERVICE_ACCOUNT_PKCS12_FILE_PATH,
'notasecret',
scopes=['https://www.googleapis.com/auth/admin.directory.user'])
credentials = credentials.create_delegated(user_email)
return build('admin', 'directory_v1', credentials=credentials)
Standard Gmail solution
You can run your application once, and then when you place it in the Docker container, make sure that you include the token.json file that was created this is the file that contains the credentials that grant the application access to your account.
If you open it you will find an access token and a refresh token within. The refresh token will give your application the ability to request a new access token whenever it needs one.
Here is the code that I am using to interactive with Office 365:
from O365 import Account
credentials = ('...', '...')
account = Account(credentials)
if account.authenticate(scopes=['basic', 'message_all']):
print('Authenticated!')
After I run the python file, I get a URL, and I click the URL:
AADSTS50194: Application '...'(test) is not configured as a multi-tenant application. Usage of the /common endpoint is not supported for such applications created after '10/15/2018'. Use a tenant-specific endpoint or configure the application to be multi-tenant.
I set "Accounts in this organizational directory only" because I only want the people in my company can access the app.
I also set this (as you can see, I have set the redirect URL ):
Am I missing something here?
Here is my new code:
from O365 import Account
credentials = ('..', '..')
# the default protocol will be Microsoft Graph
account = Account(credentials, auth_flow_type='credentials', tenant_id='..')
if account.authenticate():
print('Authenticated!')
storage = account.storage()
print(storage)
my_drive = storage.get_default_drive() # or get_drive('drive-id')
print(my_drive)
root_folder = my_drive.get_root_folder()
attachments_folder = my_drive.get_special_folder('attachments')
It can get "Authenticated!", but I get the following error:
Client Error: 403 Client Error: Forbidden for url: https://graph.microsoft.com/v1.0/drive/root | Error Message: Either scp or roles claim need to be present in the token.
{"error":{"code":"InvalidAuthenticationToken","message":"Access token is empty.","innerError":{"date":"2022-04-07T01:24:20","request-id":"be71cdcf-6f69-4d6f-b344-588d0b693253","client-request-id":"be71cdcf-6f69-4d6f-b344-588d0b693253"}}}
Thanks
You need to find your tenant Id (it will be listed on the application registration)
and then pass that in eg
from O365 import Account
credentials = ('my_client_id', 'my_client_secret')
# the default protocol will be Microsoft Graph
account = Account(credentials, auth_flow_type='credentials', tenant_id='my-tenant-id')
if account.authenticate():
print('Authenticated!')
I am trying to check if the user has installed my marketplace app
from oauth2client.client import SignedJwtAssertionCredentials
import json
from httplib2 import Http
from apiclient.discovery import build
fname = 'my-creds.json'
scope = [
'https://www.googleapis.com/auth/appsmarketplace.license'
]
applicationId='12345678'
customerId='mydomain.com'
json_key = json.load(open(fname))
credentials = SignedJwtAssertionCredentials(json_key['client_email'], json_key['private_key'], scope)
http_auth = credentials.authorize(Http())
appsmarket = build('appsmarket', 'v2', http=http_auth)
response = appsmarket.customerLicense().get(applicationId=applicationId, customerId=customerId).execute()
print response
I have created a service account in the same project as my app in Google console.
But I keep getting
googleapiclient.errors.HttpError: <HttpError 403 when requesting https://www.googleapis.com/appsmarket/v2/customerLicense/471879773528/ashish%40noodletools.com?alt=json returned "Not authorized to access the application ID">
Do you add service account to your domain's authorized API clients in security section?
Look at Delegating domain-wide authority to the service account here: https://developers.google.com/identity/protocols/OAuth2ServiceAccount
To delegate domain-wide authority to a service account, an administrator of the Google Apps domain must complete the following steps:
Go to your Google Apps domain’s Admin console.
Select Security from the list of controls. If you don't see Security listed, select More controls from the gray bar at the bottom of the page, then select Security from the list of controls. If you can't see the controls, make sure you're signed in as an administrator for the domain.
Select Show more and then Advanced settings from the list of options.
Select Manage API client access in the Authentication section.
In the Client Name field enter the service account's Client ID.
In the One or More API Scopes field enter the list of scopes that your application should be granted access to.
Click Authorize.
Your application now has the authority to make API calls as users in your domain (to "impersonate" users). When you prepare to make authorized API calls, you specify the user to impersonate.