I want to implement a solution where having 2 apis which take data from one another restrict access to the exposed endpoints by scopes.
Let's say that api1 exposes two scopes. read-only and write-only. some of its endpoints will allow only one out of the two some will allow both. Same for api2.
What I don't understand is where are the scopes validated ? Or to be more specific how exactly can I limit access to my api based on the requestor allowed scopes ?
I can undersatnd that on the identity server both the api resource and client should be configured and for the client to allow it to request access for specific scopes configured for the api resource, but I'm missing some information about how to validate the scopes.
Are the allowed_scopes part of the access_token ? If so as being part of the access_token, the api resource for which the token was generated should like decript the token and get the scopes or how exactly does this process work ?
Your thinking is on the right lines. APIs receive access tokens and authorize requests in 3 main stages:
First verify the digital signature of the JWT
Second each API endpoint verifies scopes, using the scope array received in the access token
Thirdly more detailed authorization is done using claims
A common way to check scopes is to use attributes on each controller method. Eg in .NET you get some help from the framework and can do this. See also this tutorial for sone other options:
[HttpGet]
[RequiredScope(myscope)]
public IEnumerable<TodoItem> Get()
{
// Do the work and return the result.
// ...
}
Related
Our team is looking to use Policies/Permissions in Keycloak to grant scopes to a user when they log in, but only if they have a specific role.
I've gone through a couple tutorials and was successful in setting it up and testing it using the Evaluate tab (under Authorization). If my user has the specified role in my policy, the scope shows up in the token. When I remove the role, the scope does not show up.
That's all great. Our problem is that it doesn't work when I make an authentication code flow call using the same client (i.e. not using the evaluate tab). I never get any authorization section in my token at all...this only appears when I use the Evaluate tab.
I'll note that I've tried auth code flow calls requesting the scope as well as requesting the resource and also not requesting them. Same result...no authorization section at all in the generated token.
Am I missing something on how this functionality is supposed to work? Where could my gap be? TIA!
The token you obtain in the Evaluate tab is not an access token, it's an authorization token that Keycloak will issue to clients when they ask for permissions.
The access token you obtain via the authorization code flow will not contain permissions.
When using Keycloak Authorization Services, your clients will obtain permissions by requesting an authorization token from the Authorization REST API (cf: https://www.keycloak.org/docs/latest/authorization_services/#_service_obtaining_permissions)
You can do that manually or instead use a policy enforcer which is integrated in the Keycloak adapters :
Spring Boot : https://www.keycloak.org/docs/latest/securing_apps/#_spring_boot_adapter
Javascript : https://www.keycloak.org/docs/latest/authorization_services/#_enforcer_js_adapter
Quarkus : https://quarkus.io/guides/security-keycloak-authorization
etc..
There are lots of examples of what you want to achieve in the keycloak quickstart github repo. (folders starting by app-authz-*).
The spring boot adapter is not able to authorize the scope based resource policies correctly and there seems to be a bug.
Where as evaluate on admin UI does evaluate the scope based policies correctly.
I kind of hacked to get it working by creating different resources for each individual scope and then assigning policies. But thats not what it should be.
Hi I am new to Spring Security.
I have a controller with a few endpoints. These endpoints are from the resource server.
POST /secured/user/create
POST /secured/user/update
GET /secured/user/{id}
Before accessing these APIs, client will have to get a token from my authorization server, then use it when calling the APIs above. However, I want to restrict the user to only access the GET api depending on his client ID. The client should not be able to call the create or update API.
Is there any way to do this? And how to do it in code? I am assuming the following
Something must be added in the JWT token in the Authorization server. Im guessing scope?
When API of Resource server is hit, it will validate the token. If the scope does not allow the API, then the server will return HTTP 401 Unauthorized
Any resources or links would be appreciated!
You can configure the Authorization Server to add any claims to the token, which you will eventually need to properly authorize requests. This can be a scope claim, a client_id claim, or something more granular, like can_read_user_data: true.
You can read a lot about claims, scopes, how they relate and what are some best practices around scopes and claims in articles found here: https://curity.io/resources/claims/
You can have a look at this article to see how to implement validation of JWT claims in Spring: https://curity.io/resources/tutorials/howtos/writing-apis/spring-boot-api/
I am adding an OAuth authorization server endpoint to my existing application. I am planing to issue JWTs from the OAuth token endpoint.
When a token issued for specific OAuth scopes, it looks better to embed the scopes for which the token is issued inside the token itself, because it is easier to validate whether the token has access to perform a certain action by looking at the token, when the client uses the issued token later to perform some action.
But, the standard claim fields of a JWT doesn't seem to include a suitable field to stamp the OAuth scopes.
So, would it be OK to include the scopes as custom claims in the JWT? Is there any other way to embed the scope details in the JWT?
JWT specification - RFC7519 provide you the ability to insert and use non-standard/registered claims. This is highlighted 4.3. Private Claim Names section of the specification.
A producer and consumer of a JWT MAY agree to use Claim Names that
are Private Names: names that are not Registered Claim Names
(Section 4.1) or Public Claim Names (Section 4.2). Unlike Public Claim Names, Private Claim Names are subject to collision and should
be used with caution.
Also, if you are after standard registered claims, they can be found here - https://www.iana.org/assignments/jwt/jwt.xhtml
Alternatively, if you are only interested to use standard claims and use only them with JWT Access Token (I assume JWT you refer is an access token), then you can define a token introspection endpoint and put scope values to its response. Scope is defined as a standard response parameter to introspection response
There is now JSON Web Token (JWT) Profile for OAuth 2.0 Access Tokens draft (and probably soon standard) which many already use in practice. In section 2.2.2 it explicitly states that:
If an authorization request includes a scope parameter, the corresponding issued JWT access token MUST include a scope claim as defined in section 4.2 of [TokenExchange].
All the individual scopes strings in the scope claim MUST have meaning for the resource indicated in the aud claim.
So not only that it is allowed to have scope claim, but it is even required if the request had one.
A simple scenario I have a typical architecture a client,authorization server(OAuth Server) and Resource Server.Client gets token from authorization server with client_credentials and sends token to resource server and it serves the request.So if I have 2 API's either the logged in user can access all or none based on valid or invalid token.
Is there a mechanism to grant access to 1 API ? The question is can token be API specific like it give access to 1 API and not the other.
The scope mechanism can be used to differentiate between permissions that are associated with the access token. E.g. there could be a scope for API A and one for API B. The client could ask for one of those scopes or both and the token would be valid for respectively calling both APIs or just one of them.
See also: https://www.rfc-editor.org/rfc/rfc6749#section-3.3 which doesn't say much about the semantics of scope but in practice a scope is almost always associated with a (set of) permission(s).
Question
If you would use a similar setup as the following examples:
Simple WebAPI
Javascript OIDCClient and usermanager
Would it be possible to protect other clientside files from being accessed? Say for example i have a directory with certain files which you need a certain role to be able to access them.
Would it be possible to protect my SPA from being accessed before logging in?
Or is there a better solution which would have you end up with a protected api, folders/files on a server, SPA and a silent renew mechanism like there is in the OIDCClient?
#dmccaffery helped me out by answering my question, here is his answer for those of you who are interested.
To summarize using the OIDCClient for an SPA is certainly the way to go. Exposing stuff which needs authorization should be done by using an API. Protecting parts of your Angular App can be done using a Route guard.
The way it works is as follows:
The access token is either a JWT or a bearer token (usually) and is
added by the oidc client to every HTTP request in an authorization
header — when a web API receives a reques, the bearer token
authorization middleware will parse this HTTP header and will call the
token introspection endpoint (and potentially the user info endpoint)
to have the token validated and the users claims retrieved… if the
token was manipulated by the client, it will not be valid, and an HTTP
error will be returned (usually a 403). If the token was valid, a
claims identity is created and assigned to the http request context.
The API will now have a thread with an identity already assigned to it
that represents that user.
Also he pointed out 2 pluralsight courses which would probably be useful:
https://www.pluralsight.com/courses/building-securing-restful-api-aspdotnet
https://www.pluralsight.com/courses/oauth2-openid-connect-angular-aspdotnet