I am trying to add the authorization in SAML as part of IDP implementation using SAML 2.0 Bearer Assertion Profiles for OAuth 2.0
Here, the SAML assertion is exchanged for Oauth2 access token. As per specs, the only access token should be returned in exchange of the SAML assertion and refresh token should not be returned. Following is mentioned in the spec regarding renewal of the access token (RFC7521)
An assertion used in this context is generally a short-lived
representation of the authorization grant, and authorization servers
SHOULD NOT issue access tokens with a lifetime that exceeds the validity period of the assertion by a significant period. In practice, that will usually mean that refresh tokens are not issued in response to assertion grant requests, and access tokens will be issued with a reasonably short lifetime. Clients can refresh an expired access token by requesting a new one using the same assertion, if it is still valid, or with a new assertion.
Now, if the access token is expired client can get new access token in exchange of assertion if the Assertion is still valid but how to get assertion if it is expired? If we re-initiate the SSO flow then assertion will be provided to the ACS (Assertion Consumer Service) URL which will cause a shifting from the current screen for an active user. This might cause an issue if the user has any unsaved activity on the page.
How can I provide an Assertion as a response to a request? Is there any provision in SAML for extending assertion directly via a single call to IDP?
You can't "extend" an existing assertion, you'd have to ask IdP for a new one.
The workflow where a new token is requested via an existing assertion is rare but technically possible if you can hold on to the assertion after it's issued. Doing so would require an intermediate step/component between the IdP that issues the assertion and the oAuth client, something that is certainly possible in a number of solution architectures.
The refresh of an expired token via a new assertion would be a much more common implementation choice.
Related
If I have an app and an api. If the app logs in through authorization server and sends the authorization: Bearer xxx header with each request, the api can verify the token locally.
When the user logs out (through the auth server), but the token has not yet expired if someone retrieves this token they will be able to make requests (if the authentication of the token is done locally on the server), is that correct? If thats the case, why is such a logout flow considered secure?
Edit: Clarifying the main question: why PKCE flow is considered secure if when a user logs out their access token is still valid (given we do local token verification)
BEHAVIOUR OVERVIEW
With OAuth there is a greater separation of concerns than in older standalone web apps:
You log into UIs
This is externalised to an Authorization Server
An access token is issued with a fixed / short lifetime
Access tokens are used as API message credentials
The access token can potentially be sent to other components and used from there
When you logout:
You remove tokens from your app
You redirect to tell the Authorization Server the user is no longer logged into any UI
This doesn't invalidate access tokens
TOKEN STORAGE
Tokens should be stored in private memory or protected storage so that attackers cannot access them easily. Your app then removes tokens as part of the logout process so that they are no longer available for attackers to try to access.
THREATS
The OAuth Threat Model has a section on stolen tokens, where it recommends the above storage and to keep tokens short lived. The most common industry default for an access token is 60 minutes.
The main risk of a malicious party stealing a token is via cross site scripting. XSS risks are not related to logout. Security testing should be performed regularly to ensure that XSS risks are mitigated.
BALANCE BETWEEN SECURITY AND PERFORMANCE
It may be possible for the UI to tell the Authorization Server that a token is revoked. However, the API would then need to call the Authorization Server on every API request to check for token revocation. This would lead to poor performance.
API ARCHITECTURE
I always aim to use Claims Caching and introspection in OAuth secured APIs, since it gives the actual API best control, along with good extensibility and performance.
With this in place, if you really wanted to make access tokens non usable after logout, without ruining performance, your UI could perform these actions as part of the logout process:
Revoke the access token at the Authorization Server (if supported)
Call APIs to ask them to remove cached claims for the access token
Okta /introspect can tell you if active is true or false, you could check that on every request if you are not slamming the API https://developer.okta.com/docs/reference/api/oidc/#introspect
It's hard to get access to the token, that's probably a good reason why it's not per definition insecure.
However, providing a logout option is a good idea. OAuth2 has a 'revoke' feature to make sure that tokens are revoked:
https://www.rfc-editor.org/rfc/rfc7009
Not every server supports this.
I am trying to implement refresh tokens with OIDC and OAuth2 and am having trouble understanding the workflow. From what I do understand, using the Authorization Code flow, what gets the refresh token in the response from the /token endpoint is the presence of the offline_access scope in the /authorize request.
My question is how does the request to the token endpoint know that it should return a refresh token for that user logging in, if the offline_access scope is only sent to the /authorize endpoint or should that scope also be present in the token request? Or is this a case where the refresh token should be generated and stored during the /authorize workflow, before the code is returned and then just looked up in the /token workflow to be returned there?
Specifically following this workflow:
Scopes are sent during the Authorize request and from the Authorization Server's viewpoint the following actions are performed:
code is returned to the caller
code is cached with a short time to live (eg 1 minute)
scopes are cached
in some flows other details such as a PKCE verifier are also cached
Next the client makes an Authorization Code Grant request to exchange the code for tokens and the Authorization Server performs these actions:
Looks up the code
Applies PKCE verification checks
Checks the redirect URI matches that of the original request
Looks up cached scopes
Looks up details from the OAuth client configuration, such as the refresh token lifetime
Generates tokens based on the above data
Deletes the cache entry, so that the same code cannot be processed again
Returns tokens to the caller
It is useful as an application developer to have an understanding of the key points of the AS behaviour, as above, though I expect I'm missing an important point or two. My main focus tends to be integrating flows in my UIs and APIs.
Of course when it comes to the Authorization Server, we should always use a certified 3rd party implementation, such as a low cost cloud or free open source solution.
Trying to implement OpenId Connect in Web Application consisting of following components
Identity Provider
Resource server
Single Page Application acting as Client.
Identity Provider and Resource Server are the same application.
SPA use Password Flow to get access_token and stores into the cookie. Storing access_token into cookie has it's security threads, but's it's a different story.
Problem
access_token issued by IdP is expired after 30 min and SPA needs to renew token without asking users for credentials again.
Solution
IdP returns refresh_token along with access_token. Whenever SPA gets 401 from Resource Server, it sends refresh_token to IdP and get's new access_token back.
Problem
Sending refresh_token to SPA is bad practice.
A Single Page Application (normally implementing Implicit Grant) should not under any circumstances get a Refresh Token. The reason for that is the sensitivity of this piece of information. You can think of it as user credentials since a Refresh Token allows a user to remain authenticated essentially forever. Therefore you cannot have this information in a browser, it must be stored securely.
Suggested solution
When the Access Token has expired, silent authentication can be used to retrieve a new one without user interaction, assuming the user's SSO session has not expired.
I think Silent Authentication is not applicable to Password Flow when IdP and Resource Server is same application. access_token issued by IdP is only piece of information which can be used to authorize against Resource Server/IdP after its expiration, how a client can convince IdP to issue new access_token? (without sending refresh_token)
Found angular-oauth2-oidc library which uses refresh_token to renew access_token.
What is best practice/solution in this case to renew access_token?
technical details
Identity Provider - ASP.NET Core + Openiddict library.
SPA - AngularJs application.
Single page applications must not receive refresh tokens. That has been established rules in OAuth 2.0 and OpenID Connect.
One good option I see here is to use Implicit Flow. This will establish a front channel session from your browser to Identity Provider. With password grant type you do a back-channel call (POST), so you don't get such session.
Usually this is a cookie which points to information about previous logged in status (these are identity provider specifics). With completion of the flow, SPA will receive the access token. As you figured out, it will expire. But once that happens, SPA can trigger another implicit flow, but this time with prompt query parameter.
prompt
Space delimited, case sensitive list of ASCII string values that
specifies whether the Authorization Server prompts the End-User for
reauthentication and consent. The defined values are: none , login, consent and select_account
If you identity provider maintain a long lived session (ex:- few hours or days) or if it maintain a remember me cookie, SPA could use prompt=none making it to skip login step from identity provider. Basically, you are getting browser based SSO behaviour with this.
Using the Resource Owner Password Credentials flow defeats the refresh token storage argument: instead of not being able to store the refresh token in a secure place, the SPA would now have to store the Resource Owner credentials in a secure place (assuming you want to avoid requesting username/password from the user frequently). The Implicit grant was designed for usage with an SPA, so it is better to stick with that.
Further to previous answers, the latest OAuth working group guidance for SPAs no longer recommends use of the implicit flow.
If you have simple, shared domain app (IdP, RS and client on a single domain) then you should consider not using OAuth at all. From the doc:
OAuth and OpenID Connect provide very little benefit in this
deployment scenario, so it is recommended to reconsider whether you
need OAuth or OpenID Connect at all in this case. Session
authentication has the benefit of having fewer moving parts and fewer
attack vectors. OAuth and OpenID Connect were created primarily for
third-party or federated access to APIs, so may not be the best
solution in a same-domain scenario.
If you are using OIDC/OAuth in a SPA, they recommend the auth code flow with PKCE.
We consider using OpenID Connect with ID tokens for authentication of our public API.
These are the usage scenarios we'd like to cover:
Web UI (single page, client-side JavaScript app)
Command line interface (CLI) used in an interactive session
CLI used non-interactively, e. g. in a CI/CD pipeline
Other API calls executed in a non-interactive session
The idea for (1) and (2) is to use the OIDC implicit grant type, so that the user authenticates interactively (username/password) at our OpenID Connect identity provider and permits the RP (relying party, client) to access the users identity. The identity provider will then issue a short-lived ID token, a refresh token and (optionally?) an access token to the RP.
For (3) and (4) an interactive authentication is out of the question. We'd instead like to issue tokens to the users which allow them to access our API on their behalf. These tokens should be long living, only invalidated when they get deleted in the system.
Still, we want to use JWT just like the ID tokens issued by the identity provider as a carrier of identity information for all API requests internally.
My questions are:
Can this be done purely with one of the tokens issued by the OpenID Connect implicit grant type?
Can an access token be issued in a long-lived (no expiry, only invalidated by deleting from the system) way and then be exchanged by the client against an ID token?
Or is the refresh token the thing to use for exactly that?
Or do we have to solve this outside OpenID Connect? Which leaves the question how to resolve opaque tokens from API requests against identity details (JWT) for use in our API/services?
If you use implicit flow (for Scenarios 1 and 2), you can't use refresh tokens. You need client credentials (client ID and secret) to request for refresh tokens. In the Implicit flow, we don't store any client credentials.
When a client is Public client (SPA,etc..), it is not safe to store client secret in it. So public clients generally use Implicit flow. Implicit flow doesn't support refresh tokens. Some of the OIDC libraries implement Silent token renewal/refresh feature to circumvent the absence of refresh tokens. But there are some limitations with that model (you need to have active session with IDP to get the renewal working without any interruption)
TL;DR -> If a client is public client, use implicit flow (which don't need client secret to get access tokens from IDP). Implicit flow doesn't support refresh tokens.
Can this be done purely with one of the tokens issued by the OpenID Connect implicit grant type?
It is not possible to use refresh tokens with implicit flow. Authorization code flow supports refresh tokens but can't be used with SPA clients. So you need a combination of OAuth 2.0/OIDC flows.
Can an access token be issued in a long-lived (no expiry, only invalidated by deleting from the system) way and then be exchanged by the client against an ID token?
These are two different things:
"Invalidated by deleting from the system" : With this we are discussing about Self-Contained tokens vs Reference tokens.
Self-Contained Tokens: These tokens contains all the information required to validate its authenticity in it - for e.g. the issuer details, its validity, etc.. A client don't need to make a back-channel call to STS to confirm the authenticity. These tokens are sometimes hard to revoke and will be valid for the duration as specified in the token.
Reference Tokens: Reference tokens are generally opaque tokens which contains a GUID like identifier in it and no other details. In order to validate the authenticity of these tokens, the client needs to make a back-channel call to STS. One main advantage is it can be easily revoked by deleting the corresponding identifier in STS DB.
"exchanged by the client against an ID token Refresh token" - I am assuming you are referring to Refresh tokens instead of ID token. We use Refresh token for this purpose
Or is the refresh token the thing to use for exactly that?
Yes. Refer to the above comments
Or do we have to solve this outside OpenID Connect? Which leaves the question how to resolve opaque tokens from API requests against identity details (JWT) for use in our API/services?
If you use opaque tokens, OIDC/OAuth 2.0 has several endpoint (like UserInfo) to get further information about the user. You can also use Introspection endpoint to know the validity of the token.
(Scenarios 3 and 4): I am not sure how you plan to use this - But for any non-interactive client(which is acting on its own and not behalf of user), you should use client credentials flow.
If the client want to act on behalf of user, you should enable a way for the user to approve this behavior.
I recommend anyone who is interested in OpenID Connect (OIDC) to look into OAuth2 specification. Since OIDC is built up-on OAuth2, it inherits many fundamental features.
First thing to note is Implicit flow does not return a refresh token.
The implicit grant type is used to obtain access tokens (it does not
support the issuance of refresh tokens) and is optimized for public clients known to operate a particular redirection URI
If you want to rely on refresh tokens, then you MUST consider this fact.
Can this be done purely with one of the tokens issued by the OpenID Connect implicit grant type?
It depends on the design and exact requirements. But you can indeed build the authentication on top of Id token and use access token for API calls. To validate access tokens, you can use introspection endpoint from API endpoint.
Can an access token be issued in a long-lived (no expiry, only invalidated by deleting from the system) way and then be exchanged by the client against an ID token?
This could be possible depending on the configurations of identity provider expose. But by specification, this should not be done for a client who use implicit flow. And simply because of security reasons. This is the very same reason why implicit flow does not return a refresh token. On the other hand, refresh tokens are the one which can live longer. For example, Google's refresh tokens never expires (reference - 8953983).
Or is the refresh token the thing to use for exactly that?
As mentioned previously, refresh tokens can long-lived. And it can be exchanged for a fresh access token. Returning of the id token for a refresh token will depend on identity provider implementation. For example, Azure AD do return an ID token for refresh token response. But going beyond that, the identity provider can offer a user info endpoint. A good article can be found from this link
Or do we have to solve this outside OpenID Connect? Which leaves the question how to resolve opaque tokens from API requests against identity details (JWT) for use in our API/services?
ID token indeed help to authenticate the end user from client side. But when it comes to validate user from API endpoint, you can think about using introspection endpoint or a user info endpoint. But be mindful, some identity providers do not provider introspection endpoint. At the time of writing this article Azure AD do not expose one (reference - 43378748) but do provide a user info endpoint.
Is there an example of an OAuth implementation or profile which uses multiple authorization tokens in one interaction? Can this be done with vanilla OAuth (as opposed to an extension)? Is there any discussion on the reasons for or against using multiple tokens in one request?
OAuth WRAP uses two tokens, but only one is an authorization token; the other is a request token which is used to obtain a new authorization token. What is the reasoning behind this? Does this bake sessioning into a single authorization token simply to make token passing more straightforward? Does anyone recommend building OAuth authorization tokens in this way across multiple interactions?
A "protected resource request" (i.e. a request to retrieve some resource which requires you to authenticate using OAuth) in standard OAuth carries only one OAuth token. The consumer key is also sent. The secrets corresponding to each of these tokens are used together to generate the signature.
WRAP also has the concept of an access token but it introduces the concept of a refresh token which is not included in a protected resource request but is instead sent in a direct request from client to service provider when the client's access token has expired and it needs to obtain a new one.
WRAP tokens, unlike OAuth tokens, do not have an associated secret but is instead used more like a temporary session identifier. Since this token may be exposed in a browser cookie or other browser state, WRAP allows for that token to be short-lived, allowing it to be discarded when the user signs out or after some short period of inactivity. The refresh token is known only to the client and service provider and is thus longer-lived.
A refresh token is not necessary in OAuth because the Token Secret serves as the secret known only to the client and service provider.
Both protocols have two values for the client to keep track of, one of which is more private than the other, but WRAP uses the more private token in a different way such that implementers do not need to generate and verify signatures.