I want to integrate my spring cloud gateway application with apereo CAS server(running on 8443 port) and I configure CAS server to act as Oauth2 authorization server. here is the flow;
I request gateway
It interacts authorization server(CAS here)
Before interaction, it needs to login at there.
I login with default cas-overlay-template credentials successfully.(casuser:Mellon)
cas redirect to gateway with login/oauth2/code/login-client?code=OC-3-TURQDNdC4jXulPgK7ipJSzfoBLi-iaSv&state=aitARK42e0zx2iTFkeZxoRM2rLehXSex6gTIfZOHlwY%3D url.
And [invalid_grant] error happened at gateway.
I check Spring Cloud Gateway trace logs and error happens at getting access token step.
[ctor-http-nio-2] o.s.w.s.adapter.HttpWebHandlerAdapter : [33597172] Completed 302 FOUND, headers={masked}
[ctor-http-nio-2] o.s.h.s.r.ReactorHttpHandlerAdapter : [33597172] Handling completed
[ctor-http-nio-2] o.s.w.s.adapter.HttpWebHandlerAdapter : [33597172] HTTP GET "/login/oauth2/code/login-client?code=OC-14-F99FROWxhVYzpfxkmQqB1BAfP-oOfIfI&state=Y9XC3NNkPUvb649Tx0dIDG4ZyIInioAD-xT2ll3bfII%3D", headers={masked}
[ctor-http-nio-2] o.s.w.r.f.client.ExchangeFunctions : [dee9e83] HTTP POST http://localhost:8443/cas/oauth2.0/accessToken, headers={masked}
[ctor-http-nio-2] o.s.http.codec.FormHttpMessageWriter : [dee9e83] Writing form fields [grant_type, code, redirect_uri] (content masked)
[ctor-http-nio-2] o.s.w.r.f.client.ExchangeFunctions : [dee9e83] Response 400 BAD_REQUEST, headers={masked}
[ctor-http-nio-2] o.s.http.codec.json.Jackson2JsonDecoder : [dee9e83] Decoded [{error=invalid_grant}]
Clearly, it cannot request to access_token due to bad request. but, i can't find what valid parameters are. And, I don't request manually, instead it happens automatically at behind the scene. where is my mistake? thanks for your helps.
Here is my spring cloud gateway configuration:
spring:
security:
oauth2:
client:
registration:
login-client:
provider: uaa
client-id: first-client
client-secret: noonewilleverguess
authorization-grant-type: authorization_code
redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}"
provider:
uaa:
authorization-uri: http://localhost:8443/cas/oauth2.0/authorize
token-uri: http://localhost:8443/cas/oauth2.0/accessToken
user-info-uri: http://localhost:8443/cas/oauth2.0/profile
prefer-token-info: false
client-authentication-scheme: form
cas oauth2 registered service:
{
"#class" : "org.apereo.cas.support.oauth.services.OAuthRegisteredService",
"clientId": "first-client",
"clientSecret": "noonewilleverguess",
"serviceId": "http://localhost:8085/.*",
"name": "OAuthService",
"bypassApprovalPrompt": true,
"id": 1003,
"supportedGrantTypes": [ "java.util.HashSet", [ "authorization_code" ] ],
"supportedResponseTypes": [ "java.util.HashSet", [ "code" ] ]
}
The resources I used :
https://apereo.github.io/2019/02/19/cas61-as-oauth-authz-server/
https://apereo.github.io/cas/5.3.x/installation/OAuth-OpenId-Authentication.html#responsegrant-types
okay, the question was actually simple. spring cloud gateway fills 3 fields (grant_type, code, redirect_uri) automatically but cas apereo server has api which takes 5 fields (grant_type, code, redirect_uri and also client_id, client_secret). to address this problem, you can define your api which takes 3 parameters at cas and rest of logic will be same. the only things you do is to override access token api field behaivour.
Related
I am trying to obtain an authorization token to consume a published API in Azure API Management, for which I am performing the following steps:
Call the authorization URL as follows:
https://login.microsoftonline.com/common/oauth2/authorize?
client_id=<CLIENT_ID>
&response_type=code
&response_mode=query
&redirect_uri=<REDIRECT_URI>
&scope=SCOPE
Immediately after, I call the following URL with the obtained authorization code and other parameters in the body and to send them as form-data:
POST https://login.microsoftonline.com/common/oauth2/token
client_id=<CLIENT_ID>
scope=SCOPE
grant_type=authorization_code
client_secret=<CLIENT_SECRET>
code=<AUTHORIZATION_CODE_PREVIOUS_STEP>
As a result, I get the following error and cannot continue:
{
"error": "invalid_grant",
"error_description": "AADSTS54005: OAuth2 Authorization code was already redeemed, please retry with a new valid code or use an existing refresh token.\r\nTrace ID: f0264d85-2f41-4009-9e8e-1a211209e100\r\nCorrelation ID: c6b15ffb-82e8-49aa-941f-6c85be4d9601\r\nTimestamp: 2022-01-18 15:06:55Z",
"error_codes": [
54005
],
"timestamp": "2022-01-18 15:06:55Z",
"trace_id": "f0264d85-2f41-4009-9e8e-1a211209e100",
"correlation_id": "c6b15ffb-82e8-49aa-941f-6c85be4d9601"
}
I understand that the authorization code is for one use only but, in my case, on the first attempt I get this error.
Any help is appreciated
I'm developing some SpringBoot microservices that exposes REST through WSO2 APIM.
Microservice itself does not implement any kind of authentication or authorization mecanism, it is delegated to APIM.
If I set API to use Password Grant as described here, front end application can authenticate and generate JWT token.
The problem now is that I can't fetch user roles from JWT payload because it is not being added by APIM. This information is important because front-end render menus and buttons based on user roles.
The user I'm passing when generate token does have some roles as you can see bellow:
But generated JWT token does not include any information about roles. Here is a sample token:
eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik5UZG1aak00WkRrM05qWTBZemM1TW1abU9EZ3dNVEUzTVdZd05ERTVNV1JsWkRnNE56YzRaQT09In0.eyJodHRwOlwvXC93c28yLm9yZ1wvY2xhaW1zXC9hcHBsaWNhdGlvbnRpZXIiOiJVbmxpbWl0ZWQiLCJodHRwOlwvXC93c28yLm9yZ1wvY2xhaW1zXC92ZXJzaW9uIjoidjEiLCJodHRwOlwvXC93c28yLm9yZ1wvY2xhaW1zXC9rZXl0eXBlIjoiUFJPRFVDVElPTiIsImlzcyI6IndzbzIub3JnXC9wcm9kdWN0c1wvYW0iLCJodHRwOlwvXC93c28yLm9yZ1wvY2xhaW1zXC9hcHBsaWNhdGlvbm5hbWUiOiJDYWRhc3RybyBkZSBDbGllbnRlcyIsImtleXR5cGUiOiJTQU5EQk9YIiwiaHR0cDpcL1wvd3NvMi5vcmdcL2NsYWltc1wvZW5kdXNlciI6ImVtaWxpb0BjYXJib24uc3VwZXIiLCJodHRwOlwvXC93c28yLm9yZ1wvY2xhaW1zXC9lbmR1c2VyVGVuYW50SWQiOiItMTIzNCIsImh0dHA6XC9cL3dzbzIub3JnXC9jbGFpbXNcL3N1YnNjcmliZXIiOiJhZG1pbiIsImh0dHA6XC9cL3dzbzIub3JnXC9jbGFpbXNcL3RpZXIiOiJVbmxpbWl0ZWQiLCJzY29wZSI6ImRlZmF1bHQiLCJleHAiOiIxNTk5NTYyOTQ4MDI4IiwiaHR0cDpcL1wvd3NvMi5vcmdcL2NsYWltc1wvYXBwbGljYXRpb25pZCI6IjIiLCJodHRwOlwvXC93c28yLm9yZ1wvY2xhaW1zXC91c2VydHlwZSI6IkFwcGxpY2F0aW9uX1VzZXIiLCJjb25zdW1lcktleSI6IktJaTdnUk1RYmg1OWZGbmpVOFhNbnhGcm9pNGEiLCJodHRwOlwvXC93c28yLm9yZ1wvY2xhaW1zXC9hcGljb250ZXh0IjoiXC9ia25nXC92MSJ9.km4w2V7dGmoGl8f4_ZqKHvdofAPLOOw__GPjWKrpjYelbi7IjDIpRODEZNn8hE1krRdDTSjKRviJ-NBvXtTXIiLdfPh1p-zNtX26vrS77ZcSZ2WsQA7Ku21YMqcm6cyZvEhZ99qfTxOtbJfkwt6Yt8itkyr-aqk83pNp85LTnwtNboib9VOOvh37zNEJUImzKw4WvENp4SGLuHO978FriHyHPN9vibzPjpItW5DOXTFNdN4rP6RK_vcOH6hpuZHwivJpTHxf9qMB3Gd2yTig-Hkr-sZGbx89pQf8kqtCLWbhRG5jOtcEJNf2CSNLB0Glg_e4F6LfhVD5JUCz15jdlg
When I extract it in https://jwt.io/ I get following payload:
{
"http://wso2.org/claims/applicationtier": "Unlimited",
"http://wso2.org/claims/version": "v1",
"http://wso2.org/claims/keytype": "PRODUCTION",
"iss": "wso2.org/products/am",
"http://wso2.org/claims/applicationname": "Cadastro de Clientes",
"keytype": "SANDBOX",
"http://wso2.org/claims/enduser": "emilio#carbon.super",
"http://wso2.org/claims/enduserTenantId": "-1234",
"http://wso2.org/claims/subscriber": "admin",
"http://wso2.org/claims/tier": "Unlimited",
"scope": "default",
"exp": "1599562948028",
"http://wso2.org/claims/applicationid": "2",
"http://wso2.org/claims/usertype": "Application_User",
"consumerKey": "KIi7gRMQbh59fFnjU8XMnxFroi4a",
"http://wso2.org/claims/apicontext": "/bkng/v1"
}
How do I add user roles to JWT payload? Do I need to implement a custom generator as described here?
Thanks in advance!
Easiest way to get role claim included in the auth JWT is to add a claim mapping in service provider level and request the token with openid scopes. To do this try below steps.
Log in to management console https://<host>:<port>/carbon
List service providers in the left menu
Go to edit on the required service provider (Each application in the developer portal has a mapping service provider)
Add a claim mapping to role claim as below
Send the token request with the scope=openid parameter
curl -k -X POST https://localhost:8243/token -d "grant_type=password&username=<Username>&password=<Password>&scope=openid" -H "Authorization: Basic <Credentials>"
Response access token will contain roles in this format
{
"sub": "admin#carbon.super",
"iss": "https://localhost:9443/oauth2/token",
"groups": [
"Internal/subscriber",
"Internal/creator",
"Application/apim_devportal",
"Application/admin_NewApp_PRODUCTION",
"Internal/publisher",
"Internal/everyone",
"Internal/analytics",
],
...
}
I have resources with jax-rs and use keycloak
I want to get the token with Postman
this is the database client for jax-rs (keycloak-quickstart)
{
"realm": "demo",
"bearer-only": true,
"auth-server-url": "http://localhost:8080/auth",
"ssl-required": "external",
"resource": "database-service"
}
I created a client for Postman
{
"realm": "demo",
"auth-server-url": "http://localhost:8080/auth",
"ssl-required": "external",
"resource": "client-postman",
"credentials": {
"secret": "b53f32d3-e15b-474b-a88d-1f1cfa68c2dc"
}
}
I chose the OAuth 2.0 type
The url for the access token is
http://localhost:8080/auth/realms/demo/protocol/openid-connect/token
But I do not know what the auth url is
with current version of Postman and keycloak 2.2.1.Final i've managed to setup OAuth 2.0
Client Secret: not required but AFAIK you cane have it setup in client and then you have to provide it here
Auth Url: https://{KEYCLOAK}/auth/realms/{REALM}/protocol/openid-connect/auth
Token Url: https://{KEYCLOAK}/auth/realms/{REALM}/protocol/openid-connect/token
You can get those urls from
https://{KEYCLOAK}/auth/realms/{REALM}/.well-known/openid-configuration
I managed to receive the token but I do not know how to call the jax-rs resources
I set it in keycloak:
Direct Access Grants Enabled: ON
Service Accounts Enabled : ON
and the postman request
Now that I have the token I can call resources by setting the jaxrs url and in the header Authorization: bearer [my token]
Now I would like to use Postman's Authorization function to speed up the steps and call resources directly, but I do not know if it's possible
Using doorkeeper with a client side gem for OAuth2 Resource Owner Password Credentials Flow
My request body is:
{
"grant_type": "password",
"username": "test#test.com",
"password": "sekret"
}
and endpoint for the POST is: localhost:8080/api/v1/oauth/token
I can get the grant_type: client_credentials to respond with a token...but the password param (which I need) responds with:
<title>Action Controller: Exception caught</title>
Any ideas as to why? Using doorkeeper 4.0 with a rails angular app. Thanks!
As per the RFC6749 section 2.3.1, your data should not be passed through a JSON object, but as body request (grant_type=password&username=test%40test.com&password=sekret) with application/x-www-form-urlencoded header.
When a client asks a resource server to get a protected resource with an OAuth 2.0 access token, how does this server validate the token? The OAuth 2.0 refresh token protocol?
Google way
Google Oauth2 Token Validation
Request:
https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=1/fFBGRNJru1FQd44AzqT3Zg
Respond:
{
"audience":"8819981768.apps.googleusercontent.com",
"user_id":"123456789",
"scope":"https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email",
"expires_in":436
}
Microsoft way
Microsoft - Oauth2 check an authorization
Github way
Github - Oauth2 check an authorization
Request:
GET /applications/:client_id/tokens/:access_token
Respond:
{
"id": 1,
"url": "https://api.github.com/authorizations/1",
"scopes": [
"public_repo"
],
"token": "abc123",
"app": {
"url": "http://my-github-app.com",
"name": "my github app",
"client_id": "abcde12345fghij67890"
},
"note": "optional note",
"note_url": "http://optional/note/url",
"updated_at": "2011-09-06T20:39:23Z",
"created_at": "2011-09-06T17:26:27Z",
"user": {
"login": "octocat",
"id": 1,
"avatar_url": "https://github.com/images/error/octocat_happy.gif",
"gravatar_id": "somehexcode",
"url": "https://api.github.com/users/octocat"
}
}
Amazon way
Login With Amazon - Developer Guide (Dec. 2015, page 21)
Request :
https://api.amazon.com/auth/O2/tokeninfo?access_token=Atza|IQEBLjAsAhRmHjNgHpi0U-Dme37rR6CuUpSR...
Response :
HTTP/l.l 200 OK
Date: Fri, 3l May 20l3 23:22:l0 GMT
x-amzn-RequestId: eb5be423-ca48-lle2-84ad-5775f45l4b09
Content-Type: application/json
Content-Length: 247
{
"iss":"https://www.amazon.com",
"user_id": "amznl.account.K2LI23KL2LK2",
"aud": "amznl.oa2-client.ASFWDFBRN",
"app_id": "amznl.application.436457DFHDH",
"exp": 3597,
"iat": l3ll280970
}
Update Nov. 2015: As per Hans Z. below - this is now indeed defined as part of RFC 7662.
Original Answer: The OAuth 2.0 spec (RFC 6749) doesn't clearly define the interaction between a Resource Server (RS) and Authorization Server (AS) for access token (AT) validation. It really depends on the AS's token format/strategy - some tokens are self-contained (like JSON Web Tokens) while others may be similar to a session cookie in that they just reference information held server side back at the AS.
There has been some discussion in the OAuth Working Group about creating a standard way for an RS to communicate with the AS for AT validation. My company (Ping Identity) has come up with one such approach for our commercial OAuth AS (PingFederate): https://support.pingidentity.com/s/document-item?bundleId=pingfederate-93&topicId=lzn1564003025072.html#lzn1564003025072__section_N10578_N1002A_N10001. It uses REST based interaction for this that is very complementary to OAuth 2.0.
An update on #Scott T.'s answer: the interface between Resource Server and Authorization Server for token validation was standardized in IETF RFC 7662 in October 2015, see: https://www.rfc-editor.org/rfc/rfc7662. A sample validation call would look like:
POST /introspect HTTP/1.1
Host: server.example.com
Accept: application/json
Content-Type: application/x-www-form-urlencoded
Authorization: Bearer 23410913-abewfq.123483
token=2YotnFZFEjr1zCsicMWpAA
and a sample response:
HTTP/1.1 200 OK
Content-Type: application/json
{
"active": true,
"client_id": "l238j323ds-23ij4",
"username": "jdoe",
"scope": "read write dolphin",
"sub": "Z5O3upPC88QrAjx00dis",
"aud": "https://protected.example.net/resource",
"iss": "https://server.example.com/",
"exp": 1419356238,
"iat": 1419350238,
"extension_field": "twenty-seven"
}
Of course adoption by vendors and products will have to happen over time.
OAuth 2.0 spec doesn't define the part. But there could be couple of options:
When resource server gets the token in the Authz Header then it calls the validate/introspect API on Authz server to validate the token. Here Authz server might validate it either from using DB Store or verifying the signature and certain attributes. As part of response, it decodes the token and sends the actual data of token along with remaining expiry time.
Authz Server can encrpt/sign the token using private key and then publickey/cert can be given to Resource Server. When resource server gets the token, it either decrypts/verifies signature to verify the token. Takes the content out and processes the token. It then can either provide access or reject.
Updated Answer for 2021
It is generally not recommended that you roll any part of the OAuth 2 / OIDC implementation on your own, especially now that token introspection is part of the standard. Much like attempting to roll your own encryption library, it is far too easy to make critical mistakes with such a complex spec.
Here's a list of recommended libraries in other languages that implement OAuth 2. Here's another of ones that have been certified by the OpenID Foundation; many of those libraries also implement OAuth 2.
If you're in .NET and using the IdentityServer library (version 2.2 and up), the introspect endpoint accomplishes exactly this. It's published as part of the discovery document (also standard), and is an endpoint against which the resource server can validate access tokens.
If you've come this far and you still really want to roll your own, take some tips from how the bigger libraries have done it.
OAuth v2 specs indicates:
Access token attributes and the methods used to access protected resources are beyond the scope of this specification and are defined by companion specifications.
My Authorisation Server has a webservice (SOAP) endpoint that allows the Resource Server to know whether the access_token is valid.