Getting refresh token after password reset in Azure AD B2C - azure-ad-b2c

New users are on-boarded via an offline process. At the end they are directed to a custom policy that does a password reset. This allows the user to choose their own password.
This is essentially the standard custom password reset policy without the need to validate the email. The user name is passed via a signed JWT token.
This all works and a valid ID token is returned.
The problem is getting a refresh token when this token expires.
We haven't found a way to do this.
Setting an "offline_access" scope doesn't seem to do anything.
Trying the "silent refresh" approach (prompt = "none") returns an error message stating that you don't have a session.
The applications are SPA built around adal.js.
An example of the password reset message is:
https://login.microsoftonline.com/tenant.onmicrosoft.com/oauth2/v2.0/authorize
?p=B2C_1A_Custom-PasswordReset
&client_id=xxx
&redirect_uri=yyy
&scope=openid%20offline_access&response_type=id_token
&prompt=login
&client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer
&client_assertion=JWT
Anyone ever got this working?

For a single-page application, a refresh token isn't issued, since this isn't considered to be secure.
Applications that use the implicit flow must implement a silent authentication to refresh tokens.
The silent authentication might be failing because your "Custom-PasswordReset" journey doesn't include the DefaultSSOSessionProvider SSO session provider to set the SSO claims in the user session.
As an example of this, see the LocalAccount-PasswordSet technical profile in the Wingtip sample, which is invoked to set the first-time password for a pre-verified user.

Related

How to disable automatic browser cookie login with Web.TPEngine.Providers.SelfAssertedAttributeProvider

I am using B2C custom policies.
I am using Web.TPEngine.Providers.SelfAssertedAttributeProvider documented here:
https://learn.microsoft.com/en-us/azure/active-directory-b2c/self-asserted-technical-profile
The signin relying party of the custom policy is working well, except users won't get user/password challenge after a successful login. I guess the technical profile uses browser cookies like "x-ms-cpim-cache|o4wex_p_gejeeak6w_0" for domain b2clogin.com to remember a successful login for at least a browser session.
The Metadata "setting.enableRememberMe" is the default that is set to false.
I need to make sure users are challenged with user/pwd every tinme the signin relying party is called. Is there any way to disable the auto-login with the cookie cache?
Set the session management technical profile to SM-Noop on the sign in technical profile.
For JavaScript apps, this will break silent token calls for an access token.
Other option, for initial logins, send the query param prompt=login which will kill the cookies when the user arrives at B2C. This at least keeps silent token calls working for JS apps.

Changing sign-in name in AAD B2C

I'm trying to implement Change Sign-in Name flow from AAD B2C samples. Basically the policy works but the problem is that the user is still logged in after changing his e-mail.
In my understanding changing the primary identity must invalidate all issued tokens/sessions immediately and force the user to re-authenticate. How come this can be secure and isn't addressed in the sample? How can I do it? I could redirect the request to the B2C sign-out endpoint but here is another issue:
When a user clicks "Change Sign-In Name" link he gets redirected to the policy endpoint with a specified redirect_uri query string param. In my case it's https://localhost:44300. The problem is he gets redirected back to my site when he finishes the flow and when he cancels the flow and I cannot distinguish between the two as there seems to be nothing in the request to check.
So, how can I get the user back to https://localhost:44300 if he cancels the flow (the email isn't changed) and perform Single Sign-Out if he finishes the flow?
Why should changing a username invalidate the session? I can only agree with password change. B2C has no understanding of what is happening (except for password changes) it simply does what you’ve asked. All journeys issue a token at the end, you can put a self asserted page and disable the continue button, then use JavaScript to send the user to the app’s logout route if this is what you want.
In the successful policy execution, you get a token back with the unique policy id.
In a failure you get an error sent to the app. Use this to distinguish between them.
To manage the user cancelling, send an encoded state parameter with the auth request, it’ll be returned with the “cancel error” (AADB2C error user cancelled” to your app, then do the logout. Seems like very poor UX and no security gains.
This is a very good question. When the token is generated it has a lifespan of a set time. For example 1 hour.
When you use this token, it is assumed that the user is good-to-go until the token expires and a refresh token is issued.
When the refresh token is consumed is when a new validation will occur and will need to re-authenticate.

OpenID Connect prompt parameter: SHOULD vs MUST

The OpenID Connect Implicit Client specification indicates the optional prompt=login parameter value for Implicit Clients SHOULD prompt the end-user for reauthentication.
Is the right way to interpret SHOULD either of the following:
prompt=login implementations meeting the SHOULD requirement should prompt users to reauthenticate when appropriate but may not in certain situations, e.g. prompt the user to reauthenticate where there is no active session, but do not prompt when the user has an active session.
prompt=login implementations meeting the SHOULD requirement MUST prompt users to reauthenticate.
If the right way to implement the SHOULD requirement is the #2 option above, to always authenticate, how does one handle the situation where the user is only prompted to authenticate if the session has expired? Would this be to omit the prompt parameter?
Implementations from Microsoft Azure, Okta, and Salesforce use MUST for reauthentication.
References:
OpenID: The Authorization Server SHOULD prompt the End-User for reauthentication. If it cannot reauthenticate the End-User, it MUST return an error, typically login_required.
MS Azure: prompt=login will force the user to enter their credentials on that request, negating single-sign on.
Okta: Can be either none or login. The value determines if Okta should not prompt for authentication (if needed), or force a prompt (even if the user had an existing session). Default: The default behavior is based on whether there’s an existing Okta session.
Salesforce: The authorization server must prompt the user for reauthentication, forcing the user to log in again.
For session management, You can use the max_age parameter as defined in the openid spec
Set the max_age to your desired session duration during sign-in to force identity provider to ask for credentials when session expires.

Is it safe to create a user account using the id_token provided by google's sign in?

I have a chrome extension which allows users to exclusively login with google and no other provider.
In my (node + couchdb) backend I need to construct a user account from the auth Response provided by google's oauth2 api. I was thinking about using a hash of the id_token as a password after verifying the token using the tokeninfo api
I realize that the id_token changes from time to time. In that case I was hoping to update the user's password automatically.
Here is the flow I had in mind:
1) User signs in on the front-end and gets an id_token from google
2) Id token is sent to the server and verified using the tokeninfo api
3) If verified, a user account is created with a password being the hash of the id_token.
Do you see any security holes with this flow? If so, what are the alternatives?
It is probably annoying to change user passwords all the time, and this ties your authentication too much to google. What if you want to implement password logins in the future, etc.
I would recommend to use something like proxy authentication instead.
http://docs.couchdb.org/en/latest/api/server/authn.html#api-auth-proxy
make sure to set
[couch_httpd_auth]
proxy_use_secret = true
in the config.
On a side note: if you sync the couchdb password with external secrets like in the question, you should sign the password with a hashed secret that you control completely.

Password Change Required response from RESTful Token Service

I am trying to determine the best way to enforce password expiration rules in my solution.
The server-side exposes a REST API for operations with a custom active Security Token Service (of sorts). Client applications pass user credentials to a REST endpoint where the user is authenticated on the server. The response includes a custom security token representing the user which is then passed to other API methods so the call can be authorized. The server is stateless and does not maintain any reference to the identity or claims information (i.e. session-less).
We have password expiration rules that are enforced by the server. So, when authenticating a user, it is possible that their password has expired. I need to communicate this to the client so they can do whatever is needed to have the user change their password. (There is another REST endpoint for changing the password on the server.)
Questions
It seems to me that authenticating a user with an expired password should fail. However, I need to know the identity of the user changing the password when making the second API call, so should I go ahead and return a token even when the password has expired?
How should I inform the client that a password change is required? I thought about including this as a claim in the token, but that would require me to reissue a new token after the password has been changed or modify the original token which isn't allowed. My other thought was a custom HTTP Status Code that I would correspond to meaning Password Change Required.
The answer to this question probably depends on the previous two, but I don't want to authorize a user that has an expired password if the token is passed to any other APIs (besides changing the password). What's the best way to handle this?
So, what I ended up doing (certainly not the be-all-end-all solution) is having my Authenticate endpoint return an AuthenticationResultCode enumerated value in the response in lieu of a simple pass/fail boolean. Possible values for the enumeration include:
ValidCredentials - the user was authenticated and the AuthenticationToken is included in the response.
InvalidCredentials - the user was not authenticated
CredentialsExpired - the user was authenticated but their password has expired. I have yet to determine if the AuthToken will be included with this result.
NoCredentials - no credentials were provided to the request
Now the client has more information about the result than a pass/fail value (which I really never checked anyway) and I can take the appropriate action in response such as automatically displaying the ChangePasswordDialog when CredentialsExpired is received.
Like I said, still working out whether or not I should still send the token when the credentials are expired because I don't want to be able to authorize a user if their credentials are expired but they've already been authenticated once and I don't think it makes sense to re-authenticate after changing the password (after all, I have to be authenticated so I can change the password in the first place). Maybe just a simple IsLocked or IsExpired property on the client will suffice...

Resources