JavaMail oauth requires full mail scope for sending email via gmail.
Used scope "https://www.googleapis.com/auth/gmail.send" for authorization.
then get refresh and access token.
Java mail:
transport.connect(host, port, username, access_token);
Got error:
Oauth asks for more
After changing scope to "https://mail.google.com/" for authorization, it works. But this scope will authorize
send, read, delete all emails.
This scope is too much, no difference from password authentication.
Related
We recently migrated from on premise exchange to Microsoft 365 and I'm wanting to turn on 2FA for all users (Enable security defaults). However this disables SMTP authentication which we have been using for sending mail from a distribution group address. (Not achievable via EWS as it doesn't have a physical mailbox)
From what I can see, the only method would be to set up a SMTP relay or send via Microsoft Graph.
I've tried going down the Microsoft Graph route, and here's what I've got so far.
Create application in Azure Active Directory > App Registrations
Add Mail.Send and User.Read.All (Application, not delegated) API Permissions and have granted Admin Consent.
Request token using the following
Generate auth code via https://login.microsoftonline.com/{AzureApi.TenantId}/oauth2/v2.0/authorize?response_type=code&client_id={AzureApi.ClientId}&redirect_uri={WebUtility.UrlEncode(RedirectUrl)}&scope=offline_access%20Mail.Send%20User.Read.All [using admin credentials]
Post request to https://login.microsoftonline.com/{AzureApi.TenantId}/oauth2/v2.0/token with the following request body.
{ "grant_type": "authorization_code", "client_id": "AzureApi.ClientId", "client_secret": "AzureApi.ClientSecret", "code": "insert auth code", "redirect_uri": "insert redirect URL" } to get the bearer token
Once I have the token, Now I perform a request to send some mail
https://graph.microsoft.com/v1.0/users/{fromAddress}/sendMail
This works when fromAddress is the email address of the user that requested the token, however when I try to send from a different address it gives this error {"error":{"code":"ErrorAccessDenied","message":"Access is denied. Check credentials and try again."}}
I even tried adding the SendAs permission to the token user for the mailbox I was trying to send as, but this didn't make any difference. Regardless - I want to be able to send as any user without delegating permissions to each mailbox.
Glad of any help. Thanks!!
The behavior you are getting is expected because you are using delegated permissions - authorization code flow. This flow will not allow your app to send email as any user except the user that is signed in/"requested the token".
In your case you can add the permissions as application permissions and then use Client Credentials flow with either secret or certificate(more secure). Your token request will look like the Get Access Token Section. Note that this means two things:
Your app will need to be secured on server side to protect the credentials.
An admin will need to consent to the permissions on Azure AD
Your app will be able to send emails as any user in your tenant so it is very sensitive.
With application permissions you only need Mail.Send
I got this issue while trying to fetch user attributes from AWS Cognito.
I can't tell how it can be an "Invalid Token" because I have copied and pasted it, also I have make sure that it's the accessToken not idToken or anything else.
There are some other similar questions on this site but they don't address my issue:
"Access token does not contain openid scope" in AWS Cognito
Access token does not have the openid scope
Update: here my app client config
OK, I got you detail.
Short answer: You must use oauth2 Cognito authentication instead of using default Cognito authentication API in SDK.
Let me explain why you meet error: You're using Cognito authentication, then Cognito return to you an "access token" that not contains "openid" scope, you can paste the Token here to check: https://jwt.io/#encoded-jwt.
You have to use oauth2 authentication to get the "access token" that contains "openid". In order to do it, you have to use Hosted UI or AUTHORIZATION Endpoint to get the "access token".
You can try Hosted UI by access link (pls edit your domain + response_type + client_id + redirect_uri): https://tsunami.auth.us-east-2.amazoncognito.com/login?response_type=code&client_id=CLIENT_ID&redirect_uri=CALLBACK_SIGNIN_URL
You can use AUTHORIZATION Endpoint: https://tsunami.auth.us-east-2.amazoncognito.com/oauth2/authorize?response_type=code&client_id=CLIENT_ID&redirect_uri=CALLBACK_SIGNIN_URL&identity_provider=COGNITO and it will redirect to Hosted UI
Getting user info is an open id connect feature and requires the openid scope in the token.
I suspect the problem originates from not specifying this scope when you authenticated and got the token.
Usually you configure scopes such as these when authenticating:
openid profile email
You also provide these in the OAuth Client trust entry configured in Cognito
The profile scope enables you to get the user name from the user info endpoint
The email scope enables you to get the email from the user info endpoint
See step 9 of my write up for an example
I am currently trying to implement a web service (API) with OAuth2 authentication using Spring Security OAuth. As far as I understood, given a user, a client app and a server, the authentication process is as follows:
User requests resource from server via client
Client retrieves request token from server
Server responds with a temporary request token and a redirect URL
Client loads web page (redirect URL) and lets user enter credentials in order to authenticate the request token. The form inputs are sent to the server, input is unknown to client.
Server replies with an authorization code, which is handed to the client
Client uses authorization code to retrieve an access token (and, optionally, a refresh token if one was requested)
User hands access token to client
Client uses access token to retrieve requested resource
In Spring OAuth, there are three grant types to request an access token:
Authorization Code, which is the method I described above, refresh token, and user credentials. I don't know how retrieval by user credentials works, is it similar to retrieval via refresh token?
A couple of statements you are making above are incorrect. Probably it's a good idea if you have another look into the OAuth2 spec: https://www.rfc-editor.org/rfc/rfc6749
To concentrate on your question I just refer to the last paragraph of your question here after.
OAuth2 supports 4 grant types, namely 'Authorization Code', 'Implicit', 'Resource Owner Password Credentials' and 'Client Credentials'. The one you are refering to as 'user credentials' would be 'Resource Owner Password Credentials'. In this grant type you loose OAuth's benefit of not having to hand over resource owner (aka user) credentials to the client. However it still has the benefit of not having to store the password on the client and sending it for each resource request, since a token is used instead. The process flow is as following:
resource owner sends credentials to client
client sends credentials to authorization server
server returns access token (and optinally a
refresh token)
client uses access token in subsequent request to
ressource server
So yes, you could say that the flow of the Resource Owner Password Credentials grant is similiar to the flow when a client already has a valid refresh token (from which ever grant).
I am successfully using Oauth2 gem to get an access tokens from Google accounts. But I want to get the email address which produced the token (I mean if I used this account "myemail#gmail.com" to get the access_token, how can I know the email address from the token?). Or can I get the email while obtaining the token?
Usually you can get that email with the response for any API call. For contacts API, by example, there is an entry called author in the response: https://developers.google.com/google-apps/contacts/v3/#retrieving_all_contacts
Anyway, I'm not sure which gem you're using. You can use oauth2, doorkeeper or cloudsponge.
I am building an iPhone client with a Rails backend. The client communicates with the server through an Oauth2 API. I've set this up using the oauth2 and doorkeeper gems.
Every API request must be sent with a token. I currently support two token "types":
Client: Using the Client Credentials grant type. This is for non-user-specific requests, like accessing app-wide assets, keys, etc.
User: Using the Password Credentials grant type. To get this token, the client must request it by passing a valid username/password combination. All user requests use this token.
This is all working fine but I'm hitting an issue now that I'm allowing a user to also log into the app using Facebook.
Upon the user logging into FB, my client responds by passing the Facebook UID to my server (using a Client token). I then do some checks on my server to match this UID to an existing user in my database.
Here's the issue: I want to respond to this request with a User Token. This token is needed as the user will now be logged into the app, and any subsequent requests will need this token. However, currently I feel like the only way for me to do this is:
Respond with the username and password. Then have the client make a request for a User Token following the Password Credentials flow. I don't like this because I'm passing a password, and it requires multiple trips.
I feel like I may be missing something basic. Is there another way I should be handling this flow?
I think I have a solution but it's definitely a hack.
Basically I'm hijacking the Password Credentials flow to also handle this Facebook scenario.
The client makes the call like so (formatting may be off as I tested in ruby):
curl -i http://www.example.com/oauth/token -F grant_type=password -F client_id=(client id)-F client_secret=(client secret) -F username=(email address) -F password=(password) -F provider="facebook" -F uid=(fb uid) -F token=(fb token)
On my server I check for the "provider" parameter. If found, instead of password authentication it uses the facebook uid to find a match in the user table. I also pass the FB token as a security measure (I verify that this token belongs to the uid before looking for a match). If a match is found, the user is set as the resource owner of the token, meaning I end up with a User Token.
This is the code block from my doorkeeper.rb:
resource_owner_from_credentials do |routes|
if params[:provider]
// FB uid authentication path code here
else
// password authentication
user = User.find_by_email(params[:username])
user if user && user.authenticate(params[:password])
end
end
The resource owner password credentials type defined by OAuth 2.0 doesn't really fit to external logins, e.g., Facebook, since the authentication is done through the external site and not from the username and password on your own authorization server.
One solution is to switch to the implicit grant type of OAuth 2.0 (https://www.rfc-editor.org/rfc/rfc6749#section-4.2). This type is supported by Doorkeeper too.
From your app you have to open a web view and redirect the user to the authorization endpoint of Doorkeeper (default: /oauth/authorize) with the parameters: client_id=..., redirect_uri=... and response_type=token. Additionally you have to tell Doorkeeper to redirect the user to FB login.
Therefore add this to doorkeeper.rb:
resource_owner_authenticator do
user_from_session || begin
session[:return_to] = request.fullpath
fb_login_url = "..." # add here your facebook login url
redirect_to(fb_login_url)
end
end
After the user logged in via FB and you authenticated the user on your server, you have to redirect the user back to session[:return_to] what points to /oauth/authorize and that redirects to the initially given redirect_uri including the access_token in the url.