Search code examples
oauth-2.0openid-connectopenidopenid-provider

out of band communication without OIDC CIBA


Our app has an OIDC provider and for our users, we use the standard OAuth redirect flow since user authorization and authentication are performed on the same device. However, now we have mobile users within our app we want to extend authentication to the app.

I've been looking a OIDC CIBA flow and not sure if it is right for us and I wanted to make sure.

During the verification/authentication stage of OIDC we traditionally display a login screen. However, I am thinking for mobile use cases we can just show a "polling" screen to indicate a back channel request has been made.

Since we have the device token (through a pairing phase at some point before) we can send a push notification to the phone and ask the user to approve the request. Using mTLS for encryption I can ensure a secure connection to the device. The polling screen will poll an API by a UUID for the result (the mobile device will make a success API call after approval). Once it has the result it will redirect the user back to the OIDC redirect flow.

This means we don't need to introduce CIBA and just have a new verify screen that will perform the async work then redirect once done.


Solution

  • There may be a couple of use cases you are mentioning here. For each I would aim to follow the most standard solution, with simplest code in apps and best options for extensibility.

    WEB APP LOGINS ON A DESKTOP

    Sometimes a login in a desktop browser involves a mobile device, eg if I log in to gmail in a desktop browser I am prompted to confirm that it's me on my mobile device. This triggers a call to Google's APIs, and meanwhile the login screen polls the same APIs, to detect completion.

    MOBILE APP LOGINS

    Extending the flow to work for mobile should work in the same way. Gmail uses the AppAuth pattern from RFC8252 to sign me in, then presents the same prompt to confirm it's me. In this case there is no need to switch devices. Also of course the mobile login has no dependencies on the user having access to a desktop, so that authentication works in mobile scenarios.

    CODE FLOW

    Both of the above use the code flow, with multi-factor authentication. Passwords are the primary factor (something the user knows) and a Polling Authenticator is the second factor (requires the user to have ownership of the device). Once you are using the code flow, your apps support many ways to authenticate and the authentication workflow can be changed without needing to change at the authorization server without changing any application code.

    MOBILE FACTORS

    There are a few different types here:

    • Time Based One Time Password (TOTP): apps such as Google Authenticator ask the user to enter a 6 digit number which is calculated the same both on the device and in the authorization server.

    • Polling: The login screen polls the Authorization Server, which in turn polls an external system to see if the user login has completed, as in the gmail case above.

    • App2App: In some cases the primary authentication factor can be an external app. This type of solution is also implemented via the code flow, as explained in this app2app article.

    CIBA

    This is a different use case, typically used when User A needs access to some of User B's resources temporarily. The classic case is when a call centre operator needs to act on behalf of a user. The call centre app then triggers a flow that results in the remote user being prompted to sign in. See this tutorial and video for an example. It does open up some interesting possibilities, such as delivering tokens via push notifications.

    SUMMARY

    Implementing a mobile login by getting the user to provide something they know on a desktop, then delivering a push notification, feels over complicated and non-standard. It might work against the mobile architecture also, eg preventing logins if the user is on a train.

    I would favour the AppAuth pattern and implementing mobile logins in the standard way, by getting the user to provide something they know on the device. It is likely to provide the most secure behaviour and also the best all round architecture. If you have special reasons for wanting to do things differently, you should update your question to explain why.