MSAL B2C 密码重置流程导致 "invalid grant" 错误
MSAL B2C PasswordReset Flow causes "invalid grant" error
我正在尝试使用 iOS 上的 MSAL(1.1.7) 库构建登录/注册和密码重置流程。
对于 B2C_1A_SignUpSignIn
策略,一切似乎都正常。浏览器往返后收到令牌。
当用户请求重置时,通过点击网络视图中的“忘记密码”:
我根据文档捕获了 AADB2C90118
错误代码,并使用具有 B2C_1A_PasswordReset
政策的授权机构开始了一个新流程。
let authority = try MSALB2CAuthority(url: authURL)
let config = MSALPublicClientApplicationConfig(clientId: AuthCredential.clientID.description,
redirectUri: AuthCredential.redirectUri.description,
authority: authority)
config.knownAuthorities = [authority]
let application = try MSALPublicClientApplication(configuration: config)
return application
这一切都很好,重置流程,开始,可以完成并产生 accessToken 和 refreshToken。
问题来了
这些新获得的令牌仅对 B2C_1A_PasswordReset
策略有效,当我默默地获取令牌时,用于对付我们的 api,它发生在 B2C_1A_SignUpSignIn
策略中。这意味着我第一次尝试执行包含对 MSAL.getTokenSilently
的调用的请求时,我收到此错误:
MSALErrorDescriptionKey=User interaction is required,
MSALOAuthErrorKey=invalid_grant,
NSUnderlyingError=0x6000018a5590 {
UserInfo = { MSALErrorDescriptionKey=AADB2C90088: The provided grant has not been issued for this endpoint.
Actual Value : B2C_1A_SignUpSignIn and Expected Value : B2C_1A_PasswordReset,
MSALOAuthErrorKey=invalid_grant,
MSALInternalErrorCodeKey=-42004
}
}
错误似乎很清楚,如果我的理解至少是正确的,则没有用户,只有链接到 B2C_1A_PasswordReset
策略的 accessToken 和 refreshToken。并且需要手动用户登录。
我现在应该为用户启动手动登录流程吗?
iOS 忘记密码流程将变得非常愚蠢:
- 点按帐户(根据
B2C_1A_SignUpSignIn
政策要求令牌交互)
- iOS提示允许在safari中打开webview
- 用户在网络视图中点击“忘记密码”
- 重定向回捕获错误代码的应用程序 (
AADB2C90118
)
- 使用
B2C_1A_PasswordReset
的策略以交互方式启动令牌
- iOS提示允许在safari中打开webview
- 用户跳过所有重设密码圈
- 重定向回带有 accessToken 和 refreshToken 的应用程序(我不能将其用于任何用途)
- 使用
B2C_1A_SignUpSignIn
的策略以交互方式启动令牌
- iOS提示允许在safari中打开webview
- 用户使用新凭据登录
- 重定向回带有 accessToken 和 refreshToken 的应用(我 可以 使用)
Android 不强制提示打开浏览器,对于我开发该流程的同事,用户在重置密码后登录,似乎是正在后台成功登录。
我无法在 iOS 的文档中找到密码重置流程的示例。有其他平台的例子。
我可以用不同的方式构建它以获得更好的流程吗?
我们可以访问后端,我们可以在那里做些什么吗?
策略和在其上下文中检索到的令牌是相关联的。不同的策略可能有不同的权限和流程,因此从 MSAL/apps 的角度来看,它们也可能是不同的后端。
好的,更好的流程是确保在使用 getTokenSilently
时,您还必须确保使用与检索令牌的策略相匹配的令牌。
在我在网上找到的所有 MSAL 示例中,这都不是问题,因为它们直接在 ViewController 中执行并保留对 application
对象的引用。
我每次需要时都这样设置它:
let authority = try MSALB2CAuthority(url: authURL)
let config = MSALPublicClientApplicationConfig(clientId: AuthCredential.clientID.description,
redirectUri: AuthCredential.redirectUri.description,
authority: authority)
config.knownAuthorities = [authority]
let application = try MSALPublicClientApplication(configuration: config)
具有执行特定任务所需的权限。因此,就我而言,当用户需要重置密码时,我会更改权限,转到 webview 并重置密码,取回令牌,它们会自动放入 MSAL。现在,当我调用 getTokenSilently
时,我会使用 SignInSignUp 策略,但 MSAL 中的令牌将链接到密码重置策略 =>“无效授予”
我做了什么来修复它,因为我仍然认为仅在需要时实例化 MSALPublicClientApplication
的模式要好得多,因为这与各种 API 调用不同的地方有关该应用程序,而不只是在一个 ViewController 中,是在 MSALPublicClientApplication
上使用一个应用程序 class 方法进行扩展,该方法从上次成功的 getTokenSilently
或 [=19] 中获取策略=] 并始终使用它来构造应用程序对象。
class func application() -> MSALPublicClientApplication? {
do {
let authURLString = UserDefaults.getMSALPolicyKey() ?? AuthCredential.signInAuthority.description
let authURL = URL(string: authURLString)!
let authority = try MSALB2CAuthority(url: authURL)
let config = MSALPublicClientApplicationConfig(clientId: AuthCredential.clientID.description,
redirectUri: AuthCredential.redirectUri.description,
authority: authority)
config.knownAuthorities = [authority]
let application = try MSALPublicClientApplication(configuration: config)
return application
} catch {
// catch and log error
return nil
}
}
策略应该这样保存:
application.acquireTokenSilent(with: silentParameters) { (result, error) in
guard let result = result, let key = result.account.identifier, error == nil else {
// Error handling
UserDefaults.clearMSALPolicies() // clear policies so we default to standard policy
}
completion(.failure(nsError))
}
// get policy directly from result
UserDefaults.setMSALPolicyKey(key: result.authority.url.absoluteString)
completion(.success(result.accessToken))
}
这会将问题中的密码重置流程列表减少到 7 个步骤,并且用户已登录。
在 Android 它实际上不起作用,我们只有相当长的令牌,所以直到很久以后,当带有密码重置策略的令牌过期并且客户端尝试时,错误才出现在那里使用 SignInSignOut 策略刷新它 =>“无效授权”。
我正在尝试使用 iOS 上的 MSAL(1.1.7) 库构建登录/注册和密码重置流程。
对于 B2C_1A_SignUpSignIn
策略,一切似乎都正常。浏览器往返后收到令牌。
当用户请求重置时,通过点击网络视图中的“忘记密码”:
我根据文档捕获了 AADB2C90118
错误代码,并使用具有 B2C_1A_PasswordReset
政策的授权机构开始了一个新流程。
let authority = try MSALB2CAuthority(url: authURL)
let config = MSALPublicClientApplicationConfig(clientId: AuthCredential.clientID.description,
redirectUri: AuthCredential.redirectUri.description,
authority: authority)
config.knownAuthorities = [authority]
let application = try MSALPublicClientApplication(configuration: config)
return application
这一切都很好,重置流程,开始,可以完成并产生 accessToken 和 refreshToken。
问题来了
这些新获得的令牌仅对 B2C_1A_PasswordReset
策略有效,当我默默地获取令牌时,用于对付我们的 api,它发生在 B2C_1A_SignUpSignIn
策略中。这意味着我第一次尝试执行包含对 MSAL.getTokenSilently
的调用的请求时,我收到此错误:
MSALErrorDescriptionKey=User interaction is required,
MSALOAuthErrorKey=invalid_grant,
NSUnderlyingError=0x6000018a5590 {
UserInfo = { MSALErrorDescriptionKey=AADB2C90088: The provided grant has not been issued for this endpoint.
Actual Value : B2C_1A_SignUpSignIn and Expected Value : B2C_1A_PasswordReset,
MSALOAuthErrorKey=invalid_grant,
MSALInternalErrorCodeKey=-42004
}
}
错误似乎很清楚,如果我的理解至少是正确的,则没有用户,只有链接到 B2C_1A_PasswordReset
策略的 accessToken 和 refreshToken。并且需要手动用户登录。
我现在应该为用户启动手动登录流程吗?
iOS 忘记密码流程将变得非常愚蠢:
- 点按帐户(根据
B2C_1A_SignUpSignIn
政策要求令牌交互) - iOS提示允许在safari中打开webview
- 用户在网络视图中点击“忘记密码”
- 重定向回捕获错误代码的应用程序 (
AADB2C90118
) - 使用
B2C_1A_PasswordReset
的策略以交互方式启动令牌
- iOS提示允许在safari中打开webview
- 用户跳过所有重设密码圈
- 重定向回带有 accessToken 和 refreshToken 的应用程序(我不能将其用于任何用途)
- 使用
B2C_1A_SignUpSignIn
的策略以交互方式启动令牌
- iOS提示允许在safari中打开webview
- 用户使用新凭据登录
- 重定向回带有 accessToken 和 refreshToken 的应用(我 可以 使用)
Android 不强制提示打开浏览器,对于我开发该流程的同事,用户在重置密码后登录,似乎是正在后台成功登录。
我无法在 iOS 的文档中找到密码重置流程的示例。有其他平台的例子。
我可以用不同的方式构建它以获得更好的流程吗?
我们可以访问后端,我们可以在那里做些什么吗?
策略和在其上下文中检索到的令牌是相关联的。不同的策略可能有不同的权限和流程,因此从 MSAL/apps 的角度来看,它们也可能是不同的后端。
好的,更好的流程是确保在使用 getTokenSilently
时,您还必须确保使用与检索令牌的策略相匹配的令牌。
在我在网上找到的所有 MSAL 示例中,这都不是问题,因为它们直接在 ViewController 中执行并保留对 application
对象的引用。
我每次需要时都这样设置它:
let authority = try MSALB2CAuthority(url: authURL)
let config = MSALPublicClientApplicationConfig(clientId: AuthCredential.clientID.description,
redirectUri: AuthCredential.redirectUri.description,
authority: authority)
config.knownAuthorities = [authority]
let application = try MSALPublicClientApplication(configuration: config)
具有执行特定任务所需的权限。因此,就我而言,当用户需要重置密码时,我会更改权限,转到 webview 并重置密码,取回令牌,它们会自动放入 MSAL。现在,当我调用 getTokenSilently
时,我会使用 SignInSignUp 策略,但 MSAL 中的令牌将链接到密码重置策略 =>“无效授予”
我做了什么来修复它,因为我仍然认为仅在需要时实例化 MSALPublicClientApplication
的模式要好得多,因为这与各种 API 调用不同的地方有关该应用程序,而不只是在一个 ViewController 中,是在 MSALPublicClientApplication
上使用一个应用程序 class 方法进行扩展,该方法从上次成功的 getTokenSilently
或 [=19] 中获取策略=] 并始终使用它来构造应用程序对象。
class func application() -> MSALPublicClientApplication? {
do {
let authURLString = UserDefaults.getMSALPolicyKey() ?? AuthCredential.signInAuthority.description
let authURL = URL(string: authURLString)!
let authority = try MSALB2CAuthority(url: authURL)
let config = MSALPublicClientApplicationConfig(clientId: AuthCredential.clientID.description,
redirectUri: AuthCredential.redirectUri.description,
authority: authority)
config.knownAuthorities = [authority]
let application = try MSALPublicClientApplication(configuration: config)
return application
} catch {
// catch and log error
return nil
}
}
策略应该这样保存:
application.acquireTokenSilent(with: silentParameters) { (result, error) in
guard let result = result, let key = result.account.identifier, error == nil else {
// Error handling
UserDefaults.clearMSALPolicies() // clear policies so we default to standard policy
}
completion(.failure(nsError))
}
// get policy directly from result
UserDefaults.setMSALPolicyKey(key: result.authority.url.absoluteString)
completion(.success(result.accessToken))
}
这会将问题中的密码重置流程列表减少到 7 个步骤,并且用户已登录。
在 Android 它实际上不起作用,我们只有相当长的令牌,所以直到很久以后,当带有密码重置策略的令牌过期并且客户端尝试时,错误才出现在那里使用 SignInSignOut 策略刷新它 =>“无效授权”。