Yeah, I know this stuff can be confusing! I think I understand that you want to do this step up. Let’s back up for a moment and make sure we understand authorization servers which issue tokens. Okta only supports one target in a token so generally you want one authorization server per API (the target), and only that API will accept the token. To issue tokens for your banking API, you need an authorization server configured for it.
Okta has two types of authorization servers (you’ll see three in the documentation). The org server issues tokens that target the Okta API, and you cannot configure this server.
Custom servers target your APIs and are fully configurable, your scopes and your claims. There is a “default” server that you always get in your tenant, but it’s actually just a custom server that you can use for an API without having to build the configuration from scratch.
There is a lot going in an authentication flow against one of these servers. At the core it really doesn’t matter which of your authorization servers you authenticate against, you can ask for an ID token and/or an access token. If the flow is followed properly, you end up with an Okta session cookie in your browser and if you go back to ask for a token from any of the authorization servers in the same tenant it will recognize you and you don’t have to provide credentials again. At least until your session ends.
Most of the time I want an Okta API token so that my app can talk to the Okta API and do things like extend the session at Okta while I’m using it. So, I’ll authenticate against the org authorization server and get an ID token (a better picture of who the user is) and the access token for the Okta API. Now I can talk to Okta as the logged in user. Then I’ll turn right around and query the other authorization server or servers for the API tokens I need for my own API or APIs. The user doesn’t see anything, these tokens are just given to me because Okta recognizes the user is already logged in.
So, about that “step up.” You’re absolutely right, you can do it either way. One system I do know is Chase, and in their system you have the authorization for every bank account you are entitled to immediately on login. The system actually uses that to present a list of all the accounts and balances on the home page after login.
But if you want to do a “step up” where the user needs to click a button or something to access the other authorized accounts I would just use scopes. On login I don’t ask for the scope that adds the claim that gives me access in the API, so the API doesn’t look at them. Then If the user requests it, I go back and ask for a new token with that scope. The user won’t be prompted for credentials if they are allowed to request the scope, they are already logged in.
Finally, you need to know that tokens have a short life span and usually expire before the user is finished with the application. There are two reasons for this: first if the token is exposed, it won’t be useful for long. Second, configurations change and that can affect the token so getting a new token frequently reflects any changes.
For this, we ask for a refresh token along side of the access token. It’s not a JWT, it’s just a unique code. It’s faster to use a refresh token to update a previously issued token because you don’t have to deal with the auth-code-flow, etc. When the access token we are using is close to expiring, we go back and ask for a new access token passing in the refresh token. Old refresh tokens had long life spans and that was a security risk. Newer applications always use rotating refresh token where the new access token comes with a new refresh token to update it.
Sorry it’s long, but I want to make sure I’m helping. I don’t know what your situation is, but just in case it is useful to you a lot of this is covered in the Okta API Access Management with OAuth class, with hands on labs.