Force re-authentication with Azure AD - passport.js

I am using the passport-ad library for my backend to protect my endpoint. How can I make sure that the bearer access token is new (e.g. issued time is within a certain threshold?)
For my frontend using MSAL, what is the best practise to force re-authentication when the user tries to access sensitive info?

Prompt is an optional parameter you can include during the authorization code flow, when the client directs the user to the /authorize endpoint. Prompt dictates the type of interaction that is required by the user. In MSAL.NET, you can choose from the following Prompts:
SelectAccount -> force the STS to present the account selection dialog containing a list of accounts for which the user has a session
Consent -> forces the user to be prompted for consent, even if consent was granted previously
ForceLogin -> the user will always be prompted for credentials by the service, even if not necessary (I think this is the one you want, when you say "force re-authentication")
NoPrompt -> no prompt value will be sent and the STS will determine which UI to show the user based on the previous sessions
For example:
https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize?
scope=offline_access+openid+profile
&client_id=37efsf6-14a6-44ae-97bc-6eba6916741e
&response_type=code
&redirect_uri=http%3A%2F%2Flocalhost%3A12345
&response_mode=query
&resource=https%3A%2F%2Fservice.contoso.com%2F
&state=12345
&prompt=login
More info here.

Related

How to obtain the docusign user guid to set on the JWT sub attribute?

It seems that I am missing a piece in the JWT Consent Flow.
I craft the following consent url and link it to a button that will
open a popup for the current user to login and accept the consent:
https://account-d.docusign.com/oauth/auth?response_type=code&scope=signature%20impersonation&client_id=#{my_integration_key}&redirect_uri=#{redirect_url}"
Once redirected, the documentation specifies that I should simply
ignore the code param in the redirect url.
I must create a JWT token in order to obtain an access token : At
this point I must specify the 'sub' with the user ID of the user who
just granted consent. How I am suppose to get it in this flow? I
don't understand why I should ignore the code param in the oauth
redirect, I should use it to find the DocuSign user guid.
Am I missing something ?
The userId GUID can be obtained in many ways, but that depends on the flow of your app.
You could go to check it in the Settings (admin) portion of the web app, either in the "Apps and Keys" page, where you get the logged in user ID, or in the
"User" where you can find any and all users in the account.
However, if you want to do that programmatically, you are in a catch22, as to make an API call to obtain this information you need to first be authenticated. Typically, this can be done by hardcoding a primary user (system user) that was set manually and that user then make API call to obtain all other users and their GUID (userID) respectively.

What are the best practises using Docusign's 0Auth API?

I'm using authentication code mechanism through Docusign's API for integration and works as expected.
Have a question regarding the documentation about implementation best practises, described in this page
Questions are related to the diagram at the end:
Question1
In Get the user's account ID, base URL and name (1st square) how do you recommend fetching the user/account information as before consent we don't know who is giving consent?
If it is related to users that may have given consent before, is it even necessary? If tokens already exist for the user, what is the purpose of verifying this scenario?
In the documentation it seems this is reinforced further with what is stated next:
How will we know what is the account/user information before the user gives consent?
Question2 (Similar to above)
In Collect the account ID (GUID) and name of the user, when no access token is found, I'm assuming we should redirect the user immediately so that the use gives consent again. Similar to the question above, in the diagram it indicates we should do this action "Collect account/user info" somehow before redirect for consent? We only know it afterwards as well, so is it needed?
It would be great if it would be possible to clarify the above!
As Inbar commented, that diagram needs some work. I'm sorry for the confusion.
Here's my recommendations for user present (Authorization Code and Implicit grant flows) and user absent (JWT grant flow).
All authorization flows
Determine if your users will typically use your application with a particular eSignature account or with any of their accounts. (It is common for customers to have access to more than one DocuSign eSignature account.)
If a particular account will be used, then provide an installation screen for your app where the admin can enter the account ID (use the guid format).
Your installation screen should also enable the installer to set
the DocuSign OAuth service provider, either production account.docusign.com or demo account-d.docusign.com
User present: Authorization Code and Implicit grant flows
Your app may or may not have its own login sequence for users. Your app needs a DocuSign access token for making API calls to DocuSign APIs.
When your user wants to authenticate with DocuSign:
Start the Authorization Code or Implicit grant flow.
When the flow is done, your app has an access token.
If the Authorization Code grant flow was used then you also have a refresh token.
Use the oauth/userinfo API call to obtain information about the user:
Their name and email
The eSignature accounts they have access too, and which of those accounts is the user's default account
For each account, the name of the account and the baseUrl for making API calls to the account.
If your app's users use a preferred account, then check that the user has access to the preferred account. Else, note the account id of the user's default account. (Also be prepared to handle the cases where there is either no userinfo response, no account or no default account for the user. These are infrequent DocuSign errors and can be fixed by contacting DocuSign Customer Support and referencing this article.
Use the expires_in OAuth response attribute to calculate your expires datetime. Then subtract 10 minutes so you have a buffer between the time you'll last use the access token and when it actually expires. You now have the last_use time.
Store the user's information, including the account id, base url for the account, access token, and last_use datetime.
If you have a refresh token, store it (and the user's information) in non-volatile storage.
When your application wants to make an API call
If you have a current access token for the user (last_use datetime is after the current datetime) then use it.
If the last_use time has passed, then use the refresh token if you have it. When refreshing the toke, you'll receive a new refresh token. Store it in non-volatile storage, overwriting the prior refresh token.
If no refresh token, then your app will need to ask the user to authenticate again.
Do not use oauth/userinfo again after either the token was refreshed or the user authenticated again. Keep and use the userinfo obtained after the person first logged in.
When your user wants to use a different account
Provide a "Switch accounts" feature to enable users to choose which of their accounts should be used. (Only applies if any account can be used with the application.)
User not-present: JWT grant
Your app's configuration screen will also need the user id in guid form. You can either store these values or look them up from DocuSign.
Decide whether a specific account is needed or not (see above).
Decide how the user will grant consent. See this video for more info.
First time your app needs an access token after a reboot
Use the JWT user grant to obtain an access token
As above, calculate the last_use datetime including a 10 minute buffer.
Use oauth/userinfo as above to determine if the user has access
the account or what the user's default account is. Also obtain the account's base_url.
Store the information.
Use the access token to make the API call.
Subsequent API calls
Check the last_use datetime. If it hasn't yet occurred then use the stored access token. If it has occured, then redo the JWT user grant flow but do not make another oauth/userinfo call--use the prior information.
Question 1 - You do not need to remember which user gave consent. That is not something you should do anyway, because users can revoke consent and then your information will be inaccurate. The system will ask for consent if needed (and if you ask for additional scopes it may be needed even if consent was given for example).
Question 2 - You should redirect immediately, whether consent is needed or not is unclear, but the user will either have to login, or just redirected if they have a cookie and consent is also based on their circumstances.
I'll consent (no pun intended) that we can improve this diagram and make it easier to understand. I would suggest implementing a simple scenario first and seeing how it work before moving on to the more advanced scenario (by simple I mean every time a user need to log in as if it was their first time).

Auth JWT example PHP

Using https://github.com/docusign/eg-01-php-jwt
I haven't successfully implemented the above repository for JWT authentication, I have the return:
C O N S E N T R E Q U I R E D
Ask the user who will be impersonated to run the following url:
https://account-d.docusign.com/oauth/auth?response_type=code&scope=signature%20impersonation&client_id=xxxxx-xxxxxx-xxxxx&redirect_uri=https://www.docusign.com
It will ask the user to login and to approve access by your application.
Alternatively, an Administrator can use Organization Administration to
pre-approve one or more users.
When accessing the informed URL I cannot login, it says that the credentials are invalid.
Yes I have a demo account, I am accessing it with login and password in another tab, this is all right.
But in my integration it generates the message and I can't proceed, I'm trying to generate the token for access. The integration is all completed, I developed it with the token generator available (developers.docusign.com/oauth-token-generator), it is just missing that part of JWT authentication that is causing me problems
Thanks
If you're not able to log in to the Demo environment, you'll likely need to do a Password Reset using the Forgot Password link on the login page. Do keep in mind that while you can sign up for a Demo account using the same email address as a Prod account, those two accounts will have separate passwords, so be careful to track of which environment you're taking action in.
If you don't have a Demo/Sandbox account at all, they're freely available from the DocuSign Developer Center: https://developers.docusign.com/ > Click 'Create Sandbox'
I suggest trying the URL provided by the example in an incognito browser window. Normally there is no problem using a regular browser window for this one-time step.
The consent url simply enables you to login via the in-person OAuth Authorization Code flow. You authenticate and then grant consent.

Getting refresh token after password reset in 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.

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.

Resources