How to reflect new user profile changes in OidcUser? - spring-security

How can I update the user profile changes like name, locale and more after Spring Security's OidcUserService has fetched it from KeyCloak IDP when the end user completes the authentication and authorization flow i.e. I updated the attributes of the user profile in KeyCloak but the data in OidcUser was not updated because a request was not made to the /userinfo endpoint.

You can
configure keycloak to include whatever claim you like in access-token
configure spring-security to have security context populated with an Authentication instance based on access-token claims (either with a JWT decoder or token introspection)
You'll find sample resource-server configuration here : https://github.com/ch4mpy/spring-addons/tree/master/samples/tutorials

Setting the Base URL field [http://base-url-app/oauth2/authorization/login-client] in the Client used by app in the authorization flow, which allows to show the Back Button back in the profile screen and thus redirect the user to the authorization flow.

Related

Can I use an OAuth2 access token to get an access token for a different client?

In our project we want to have one "master" client the user has to get an access token for once. Any further clients that require an access token will do so through the "master" client.
Currently the user has to log in each time a client wants an access token. If our "master" client has a valid token and I try to get to the authorize endpoint with it, I either got forwarded to the login page or get an "InsufficientAuthenticationException: User must be authenticated with Spring Security before authorization can be completed."
At this point I wonder if it's even intended to access the authorize endpoint in this way or if we're just doing something wrong.
I had the same issue. Basically what I have done is extended AbstractTokenGranter with new grant_type in which I got authentification from token store and created new TokenRequest with second clientIds. Also you need to create new AbstractUserDetailsAuthenticationProvider with your checks and extend UsernamePasswordAuthenticationToken to hook it in chain.
All whats left is to add granter and provider in setup and use your brand new grant_type in request to oauth master server. Good luck!

OAuth 2.0 Auth code grant - Is there anyway to Authenticate user when requesting for Auth Code

Whats the best way to programmatically authenticate user using OAuth 2.0 Authentication Code Grant ?
Wondering if there is a way to combine step A and B as stated on the spec - https://www.rfc-editor.org/rfc/rfc6749#section-4.1, i.e pass user ID and password as part of authorize call ? Something like,
/authorize?response_type=code&client_id=s6BhdRkqt3&state=xyz
&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb&user_id=john.doe#mail&password=xxxx
I believe one way is to submit() the form returned by the Authorization server with user id and password. Taking this route would create a dependency on the form and any changes to it given it is not a public API.
The Authorization Code grant is designed to be used with a full browser i.e. should not be used to authenticate the user programmatically. In fact using it programmatically would defeat the purpose of OAuth 2.0 to not divulge the user's credentials to the Client.
Grants like Client Credentials and Resource Owner Password Credentials have been designed to be used with non-browser Clients.
Alternatively you could create an access_token and refresh_token for your Client in a browser using the Authorization Code grant, then pass the tokens to your non-browser Client so that it can use the refresh_token on its own to obtain a new access token when the old one expires.

What authentication mechanism to use in client app

I am working on an ASP.NET MVC client application. User is authenticated and authorized via another API application which returns token.
Currently, after client app recieves token from API, it saves token in session and sets form authentication cookie for app authorization.
FormsAuthentication.SetAuthCookie(TokenViewModel.Username, rememberMe);
HttpContext.Current.Session["AuthenticationToken"] = TokenViewModel;
Should i keep using form authentication, or just save token in session? or user OWIN here to authorize user.
Client app uses [Authorize] attribute.
If you are using [Authorize] attribute, by default the API will check for the access token in the Authorization header of the HTTP request, not in the cookie.
If you want to use the cookie, then go for forms authentication or customize the Authorize attribute to check for the token inside the cookie.
So, it's better to keep the token in session and at the same time manage it's lifetime(token expiry) explicitly. Apart from that, you can use refresh tokens to get new access token after or before the current one expires.

Single Page Application with Cookie Based External Identity Provider Login and Token Delegation

How do you create a seamless login flow for a single page application using third party open id connect provider (such as Google or Microsoft) that then generates a new jwt token from an existing one returned by the external provider without refreshing the page?
For example, I want a user to be able to log into Google, then be brought back to my site where I validate the token server side using IdentityServer4, then extract certain claims and generate a new JWT (my own logic).
Is there an existing IdentityServer4 endpoint that validates JWT tokens from Open Id Providers at the redirect and then what's the best approach to injecting my own token creation flow afterwards? The end result is a ideally a cookie containing my new JWT token that will now be sent on every http request my SPA makes.
My best guess is to use the oidc js client and set up a user manager for Google, for example:
var mgr = new Oidc.UserManager({
authority: "https://accounts.google.com/.well-known/openid-configuration",
client_id: "---",
redirect_uri: "http://localhost:60720/account/callback",
response_type: "id_token token",
scope: "openid profile email",
post_logout_redirect_uri: "http://localhost:60720/spa",
});
/*...*/
mgr.signinRedirect();
However, on the redirect, I need Google to send a cookie to my controller, which will then use IdentityServer to validate the token, extract some claims like the user id, and then generate a new token for my API. This assumes I'm using IdentityServer to host my own identity provider. How do I use IdentityServer4 to accomplish this last part?
This is simple to do with an MVC pattern because the token is generated on the post back after the redirect callback is invoked. In a SPA, there should be minimal redirection, ideally none where a popup is displayed to allow the user to login and then the SPA takes over. I've been unable to figure out how to redirect from an external identity provider to my IdentityServer4 auth server or MVC server and generate a new token with minimal disruption of the de-facto configuration.
Google recommends that the server must validate the token (https://developers.google.com/identity/protocols/OAuth2UserAgent#validate-access-token). One possible solution is to generate my new token in the redirect callback after its validated. However, isn't IdentityServer4 supposed to validate the token, or do I have to do this myself on the server? What part does IdentityServer4 play here in the token validation. I don't want to hand code this step myself.
I ended up creating my own grant type with an Identity Server endpoint just to exchange a third party authentication cookie into an internal JSON-bearer based token.

Why should /oauth/authorize be secured?

According to http://projects.spring.io/spring-security-oauth/docs/oauth2.html:
N.B. the Authorization endpoint /oauth/authorize (or its mapped
alternative) should be protected using Spring Security so that it is
only accessible to authenticated users.
Why is that? It doesn't sound right that an endpoint that will require an authorization grant to exchange for an authorization code should be secured. It's like a login page for a login page, specially when Authorization grant will be through resource owner password credentials.
oAuth2 authorization works in two steps:
User authenticates using their credentials
User grants application X the authority to use their data
Step 2 happens on /oauth/authorize and step 1 happens elsewhere in your application (most likely through a form-login backed by Spring Security).
If you don't protect /oauth/authorize you will end up granting authorization without authenticating the user (or you won't because without an authenticated session you probably have no idea who the user is).

Resources