I have installed and configured JWT Grant Type in WSO2 IS 5.3.0 following this guide
Then I have configured a Service Provider enabling the OAuth/OpenID Connect Inbound Authenticator.
I am able from a javascript client to authenticate the user exploiting the Oauth 2 protocol with open-id scope obtaining a valid JWT token (JWTToken).
Finally I tried to make a POST request to https://****/oauth2/token?grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion=JWTToken using a REST Client and setting Content-Type=application/x-www-form-urlencoded.
When I do the request the WSOIS Server asks for a username and a password. I am able to pass this step providing a valid clientId and clientSecret.
Unfortunately at this point the server dos not reply with an access token but with a 400 Bad Request and in the response body writes "{"error_description":"Error occurred while decoding public certificate of Identity Provider default for tenant domain carbon.super","error":"invalid_grant"}"
I can't understand if the problem is the JWT Token that I pass to the server or if there is some issues with the certificates. Any help please?
Okay. I think this should help you.
If you take the OpenID connect token you got from WSO2 Identity Server and put it in jwt.io you would see that the openID connect will have the "iss" (issuer) value of "https://localhost:9443/oauth2/token" (replace localhost with your hostname if you have set the hostname) which is the token endpoint of WSO2 Identity Server.
So when you use this token as a JWT Bearer grant, in order to validate the signature the grant handler tries to retrieve an IDP with the name given in the issuer(iss) field (ie. token endpoint of WSO2 Identity Server). As it fails to find any identity provider it retrieves the default identity provider (note this is a dummy IDP added for sake of backward compatibility) which doesn't have any certificate. (you can find this under $IS_HOME/repository/conf/identity/identity-providers/default.xml)
So there are two ways to fix this,
Change the issuer value of Identity Server so that it can fetch the certifcate of it's resident identity provider.
To do this,
Login to the management console,
Go to Identity Provider --> Resident --> Inbound Authentication Configuration --> OAuth2/OpenID Connect Configuration --> set the
'Identity Provider Entity Id' value as LOCAL
Create a new Identity Provider with the name equal issuer value of the OpenID connect token (ie. the token endpoint) and upload the public certificate that could be used to verify the OpenID connect token.
Personally, I prefer the first solution :)
Update:
You also need to do one more change,
In identity.xml (found under repository/conf/identity) uncomment the following lines
<Audiences>
<Audience>
${carbon.protocol}://${carbon.host}:${carbon.management.port}/oauth2/token
</Audience>
</Audiences>
This will make sure that the audience validation check will pass for the issued OpenID connect token when used as a JWT bearer grant. (ie. the JWT Grant handler will validate whether the token endpoint is one of the audiences in the provided grant)
Related
I've spent the last couple days trying to set up Cognito to use Battle.net OIDC. I believe I am most of the way there. I can see using the cognito hosted UI that it authenticates correctly but then fails, presumably trying to retrieve the token.
The first request to cognito hosted UI:
https://<removed>.auth.us-west-2.amazoncognito.com/oauth2/authorize?identity_provider=Blizzard&redirect_uri=https://<my-site-oauth-handler-removed>/oauth&response_type=CODE&client_id=<removed>&scope=openid
Then the next request is to Battle.net OIDC as expected:
https://us.battle.net/oauth/authorize?client_id=<removed>&redirect_uri=https%3A%2F%2F<removed>.auth.us-west-2.amazoncognito.com%2Foauth2%2Fidpresponse&scope=openid&response_type=code&state=<removed>
Then the code is passed onto the cognito idpresponse:
https://<removed>.auth.us-west-2.amazoncognito.com/oauth2/idpresponse?code=<removed>&state=<removed>
At this point, if my understanding is correct cognito should try to hit the battle.net /oath/token endpoint and then return the id_token and access_token to my redirect_url. It is at the point cognito instead returns an error to my url:
https://<my-site-oauth-handler-removed>/oauth?error_description=Bad+id_token+issuer+oauth.battle.net&error=invalid_request
Judging by the lack of documentation for Battle.net OIDC I may be one of a handful trying to use the battle.net OIDC with Cognito. It very well could be a bug with their implementation but I'm trying not to jump to that conclusion.
My best guess right now is that I haven't configured Cognito correctly to make the token POST request. It needs to use Basic Authentication with the clientid:password but I can't verify if it's doing that correctly or not since its abstracted away.
Anyway, when I make the request through my app (using amplify to open the hosted UI) it does return but with the following:
[ERROR] 51:05.25 OAuth - Error handling auth response. Error: Bad+id_token+issuer+oauth.battle.net
at OAuth.<anonymous> (OAuth.js:202)
at step (OAuth.js:52)
at Object.next (OAuth.js:33)
at OAuth.js:27
at tryCallTwo (core.js:45)
at doResolve (core.js:200)
at new Promise (core.js:66)
at __awaiter (OAuth.js:23)
at OAuth.handleAuthResponse (OAuth.js:181)
at AuthClass.<anonymous> (Auth.js:1632)
Here is all my relevant Cognito configuration:
OIDC Provider:
Provider Name: Blizzard
Client ID: [removed]
Client Secret: [removed]
Attributes request method: POST
Authorize scope: openid
Issuer: https://us.battle.net/oauth
App Client:
Name: [removed]
App client id: [removed]
App client secret: (no secret key)
App Client Settings:
Enabled Identity Providers: Blizzard
Callback URLs: https://[removed]/oauth
Sign out URLs: https://[removed]/oauth
Allowed OAuth Flows:
Authorization code grant
Implicit grant
Allowed OAuth Scopes
email
openid
aws.cognito.signin.user.admin
profile
(I've tried every variation of these and it doesn't appear to change the outcome)
Federated Identity:
Authentication providers
OpenID
us.battle.net/oauth
IAM Identity Providers:
Provider Name: us.battle.net/oauth
Provider Type: OIDC
Provider URL: us.battle.net/oauth
CA Thumbprint: [removed]
Audience: [my battle.net client id]
I have exhausted my own resources and am asking for any guidance with this.
Thanks!
This was caused by Blizzard issuing their tokens from their well-known endpoints but setting the iss field to oauth.battle.net which caused Cognito (or any other token validation) to fail hence the error message
Bad+id_token+issuer+oauth.battle.net
I brought this up to their API team in Discord and they are releasing a fix on November 25th according to an email send to developers.
Dear community developer,
Earlier this year, we introduced a new OAuth discovery endpoint which
implements the OpenID Connect discovery specification. We would like
to deploy a change to the issuer field iss of the id_token during the
OpenID authorization flow from oauth.battle.net to the issuer that is
returned by the well-known configuration endpoint JSON response. This
would be a potential breaking change to some of the OAuth OIDC clients
but it conforms to the OpenID connect specification:
https://openid.net/specs/openid-connect-core-1_0.html#IssuerIdentifier
Your OAuth client application was identified as one that could be
affected by this change.
We are planning to release this change on November 25, 2019.
Here are the steps that you can take to ensure your OpenID Connect
client will continue working after the change:
Navigate to one of the well-known configuration endpoints below which
corresponds to the region where your client application operates and
check the "issuer" field.
If the issuer field matches the configured issuer for your OAuth OIDC
client then your client is compatible and you are already compliant
and do not need to make any changes.
If the issuer field from the well-known configuration endpoint is
different than the issuer set in your client configuration, please
change the issuer to match the well-known configuration endpoint.
If your client supports the OpenID discovery endpoint standard, you
can configure it to read all necessary settings from the well-known
configuration endpoint. Your OAuth client should self-configure.
I want to use AWS cognito as a OpenId connect provider.My AWS cognito IDP will intern call my another OpenId provider to authenticate the user. It will then create its new token and hand over to callers as its own.
The OpenID provider used internally by AWS cognito pool is transparent to user. User only configures AWS cognito as its IDP provider.
User case
User authenticates with My AWS IDP provider
My IDP provider authenticates the user agains Googles IDP provider
My IDP decodes the token returned by Google IDP.
My IDP Creates new token and add additional claims.
My IDP hands over my JWT to user.
Question
Is this possible in AWS cognito?
Does AWS user pool expose OpenID connect endpoint?
Cognito does provide an OpenId connect endpoint, as detailed in this blog post by #Badri
The formula for the authority is:
https://cognito-idp.{region}.amazonaws.com/{userPoolId}
And you can verify by checking the metadata URL that something is there
https://cognito-idp.{region}.amazonaws.com/{userPoolId}/.well-known/openid-configuration
Then during client pool setup, you can federate with other OIDC providers, and also enable the OIDC provider in the app client settings. Which should enable your scenario which sounds very similar to what I would like to do. However, the blog post misses one crucial piece of configuration, which is setting a domain name for the app integration. This StackOverflow question shows the error you will receive if you do not configure this domain and links to the solution in an answer. Once I set the domain, Badri's code worked for me.
To give a more detailed answer on Cognito's OpenID Connect support.
Discovery Endpoint
Cognito exposes an OpenID Connect Discovery endpoint as described at https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfigurationRequest at the following location:
https://cognito-idp.{region}.amazonaws.com/{userPoolId}/.well-known/openid-configuration
Response Types
The above endpoint returns the following three response_types:
"response_types_supported":["code","token","token id_token"]
code: defined in https://www.rfc-editor.org/rfc/rfc6749#section-11.3.2 - this worked for us, but only when a domain was specified as below.
token: this value is forbidden by OpenID Connect at https://openid.net/specs/openid-connect-core-1_0.html#ImplicitAuthRequest - "NOTE: While OAuth 2.0 also defines the token Response Type value for the Implicit Flow, OpenID Connect does not use this Response Type, since no ID Token would be returned." - OpenID Connect libraries will ignore this response.
token id_token: this value triggers a redirect to an error page with the code "invalid_request". There is no indication given as to what is invalid with the request. AWS technical support claim that only "code" and "token" are supported by authorize endpoint, it is however not clear why this response_type is advertised if not supported.
Domain
Cognito gives the option to specify a domain that will prefix the hostname of the Cognito endpoint.
Without a domain being specified, Cognito will advertise generic URLs at the OpenID Connect discovery endpoint such as https://cognito-idp.eu-west-2.amazonaws.com/{userPoolId}/authorize, but all attempts to log in at these URLs return the error message:
{"code":"BadRequest","message":"The server did not understand the operation that was requested.","type":"client"}
The error message does not indicate what is bad about the request, so this appears to be a bug in Cognito.
With a domain specified, Cognito will advertise URLs that include the domain prefix, and the response_type "code" returns a login page as expected.
Logout
OpenID Connect Session Management at https://openid.net/specs/openid-connect-session-1_0.html#RPLogout describes how an OpenID Connect logout must be initiated, and requires as per https://openid.net/specs/openid-connect-session-1_0.html#OPMetadata that the end_session_endpoint parameter be included in the discovery metadata.
In the case of Cognito end_session_endpoint is omitted from the metadata.
RP-Initiated Logout at https://openid.net/specs/openid-connect-session-1_0.html#RPLogout describes how the logout endpoint works. If an attempt is made to pass the logout endpoint manually to the OpenID Connect client implementation, logout fails as follows:
{"code":"BadRequest","message":"The server did not understand the operation that was requested.","type":"client"}
Again, the error message gives no indication of the error, however the description of the logout endpoint at https://docs.aws.amazon.com/cognito/latest/developerguide/logout-endpoint.html shows no compatibility with OpenID Connect.
While you can log into Cognito using OpenID Connect, there is no option to log out.
Cloudformation
Cognito Cloudformation support is incomplete, and affects OpenID Connect as follows:
There is no way to specify a domain using Cloudformation, and the domain is required for OpenID Connect to work.
The callback URL is required by OpenID Connect, but cannot be set using Cloudformation.
Summary
To access Cognito using OpenID Connect, ensure that a domain is specified, and use the response_type "code" only. OpenID Connect logout is not possible. Other options violate the OpenID Connect specification, or were released broken.
I'm having a little trouble following your use case, but I'll explain some points that might help.
You can use Cognito User Pools to authenticate users through Google, and then issue JWT tokens from the Cognito User Pool. See the Developer Guide.
Cognito User Pools is not currently a full OpenID identity provider, but that is on our roadmap. User Pools do support OAuth2.0 flows, and they do provide OpenID standard JWT tokens.
I'm successfully getting an access token to resource https://manage.office.com from https ://login.microsoftonline.com/MYTENANTID/oauth2/token using grant_type client_credentials with my client ID and client secret.
But I always get "Authorization has been denied for this request" back when I try to use that token with to start a subscription using https ://manage.office.com/api/v1.0/MYTENANTID/activity/feed/subscriptions/start?contentType=Audit.SharePoint
There is only one Tenant. My app is in the same tenant I'm trying to access.
Do I have to do the client certificate thing with the manifest or can I use the secret key? This is service to service. Or is it that I'm not getting an authorization code first? I didn't think I needed to do that since this scenario doesn't require content
Any help greatly appreciated.
Based on the test, I am also not able to call this rest via the token request with the client id and secret.
To use this API, you can generate a self-signed certificate. Detail step about use certificate to request the app-only token please refer here.
I've been requested by a client to incorporate OAuth authentication within a REST service. The setup I am working with is client/user accessing a service directly. The service is not connecting to another service. I was asked to have OAuth implemented so that users/clients are authenticated by supplying the username and password in the authorization request and not have them log in via a web page. My client has read information from other sites like paypal (https://developer.paypal.com/docs/integration/direct/paypal-oauth2/) which lead him to believe this was possible. So my underlying question is how do I configure an Authoirzation Server to allow for authorization when supplied a password and username directly?
Peter
The flow is called "Resource Owner Password Credentials Grant" and described in 4.3. Resource Owner Password Credentials Grant of RFC 6749 (OAuth 2.0).
In this flow, a client accesses the token endpoint without accessing the authorization endpoint. So, check the configuration of the token endpoint of your authorization server.
4.3.2 of RFC 6749 (which describes the "Resource Owner Password Credentials Grant flow" of the oauth2 Authorization Framework) states:
If the client type is confidential or the client was issued client
credentials (or assigned other authentication requirements), the
client MUST authenticate with the authorization server as described
in Section 3.2.1.
Can't seem to find a reference as to what a "confidential client" is. From this it seems that it's allowed to have non-confidential clients participate in the "Resource Owner Password Credentials Grant flow" (4.3). I.e. clients that won't (and can't) authenticate themselves with the Authorization Server.
Is this correct?
Check out the client types section, where the definition of "confidential clients" is given as:
Clients capable of maintaining the confidentiality of their
credentials (e.g., client implemented on a secure server with
restricted access to the client credentials), or capable of secure
client authentication using other means.
Cloudfoundry's command-line cf application is an example of a "public" (i.e. non-confidential) client which uses the password grant.
Section 2.3 of the oauth2 specification has the following paragraph:
The authorization server MAY establish a client authentication method with public clients. However, the authorization server MUST NOT rely on public client authentication for the purpose of identifying the client.
Where a public client is defined in section 2.1 as:
Clients incapable of maintaining the confidentiality of their credentials (e.g., clients executing on the device used by the resource owner, such as an installed native application or a web browser-based application), and incapable of secure client authentication via any other means.
So, you can (optionally) authenticate the client but not take that the mean that the client is who it says it is.