I'm trying to add OTP/2FA support into OAuth2, but after much reading through the RFC6749, it's still not clear how OTP/2FA could be cleanly added without violating the specification.
Although OTP/2FA entry can be added into the authorize dialog flow, there is no provision for adding it into token. For example, public client apps with Resource owner password-based privileges may want to provide the token directly when requesting a new access_token, rather than having to embed a HTML dialog box.
Therefore my questions are;
Does the RFC allow for custom grant_type? Should this be used to provide 2FA/OTP functionality?
Does the RFC allow for additional attributes on an existing grant_type? For example, grant_type=token&otp_code=1234 (RFC does not make it clear if additional attributes are allowed on grant_type's within the specification)
Should OTP functionality be placed into headers? This is the approach that Github used, but it feels really ugly/hacky.
Are there any other approaches that I have overlooked?
Thank you in advance
The RFC allows for an extension (custom) grant, see section https://www.rfc-editor.org/rfc/rfc6749#section-8.3. That grant could define additional attributes.
OAuth 2.0 does not define how the Resource Owner authenticates to the Authorization Server, with the exception of the Resource Owner Password Credentials grant. Your proposal could be designed as an extended variant of that grant.
I'm working on something similar. I've got an endpoint at which you can request certain metadata for a user such as whether or not 2fa / mfa / otp is turned on and the salt (and iterations and algorithm) for Proof of Secret / Secure Remote Password.
If you go that route you can simply extend the grant types with an mfa or totp field (that's what I'm doing). You could also create a custom grant type as mentioned above (perhaps more proper).
Another solution is to check for MFA / 2FA / OTP during the authorization dialog step.
If I were done with my OAuth2 implementation I'd link you to that code too, but here are some libraries for an Authenticator:
Browser Authenticator has the components you need to generate and verify a key and token in the browser: https://git.coolaj86.com/coolaj86/browser-authenticator.js
Node Authenticator has the complementary server-side code: https://git.coolaj86.com/coolaj86/node-authenticator.js
You would still need to provide your own database storage mechanism and link it in to your OAuth implementation or you could make a very simple one and run it as a microservice.
I agree with Hanz Z.: you can design your own grant type to consume OTP.
But OTP can also be used for client authentication (confidential clients as you have to store credentials).
For example, we could imagine an header in the token request (X-OAuth2-OTP = 01234567). Client authentification will fail if the client activated OTP but no header is set.
Based on specifc SCOPE (Ex. OTP) you can mark bearer(access_token) as ""verified_otp = false"" on the backend, then after authorization server received valid otp for that session mark your bearer(access_token) as ""verified_otk = true"". For your resource server, check verified_otk field befores authorize calls that depends this verification.
Related
Does an app using authorization code (with or without PKCE) to obtain access + id tokens on behalf of a user need to also validate those tokens (signature, not expired, audience, etc.)?
If so, what for? Since the client is using TLS and pointing to the provider it's been configured with, what attacks/threats does that client also validating the token mitigate?
At first glance you are right and the spec basically allows for not checking tokens directly returned from the token endpoint over TLS as you suggest indeed, but:
Firstly, one may argue that if a signature is present, it is there for a reason and it should be validated since the Provider is also free to return tokens without a signature (alg="none") if it did not want/need the Client to validate.
Secondly, there are known attacks ("IDP mixup") that trick the Client into talking to the wrong token endpoint as a way of stealing the Authorization Code: verifying that the ID token returned does not match the expected signature would at least stop the Client from processing an ID token produced by an attacker.
Thirdly, it would be good for the Client to protect itself against broken or compromised IDPs in general, avoiding replay attacks or similar.
I guess when you're doing all of it in a single domain, i.e. Client, AS and RS are all under control of the same organisation and the relationships between them are fixed and one-to-one only, technically verification would be overkill based on current knowledge and known attacks.
But in case your use case spans multiple security domain, in general it is better to verify than it is to assume.
I am not sure which approach I should be taking in our implementation and need some guidance.
I have a REST API (api.mysite.com) built in the Yii2 Framework (PHP) that accesses data from mysite.com (database). On mysite.com our users will be able to create Connected Apps that will provision a client id + secret - granting access to their account (full scope?).
Based on my research, the next step seems to be setting up something to actually provide the bearer tokens to be passed to the api - I have been leaning towards oAuth2, but then I read that oAuth2 does not provide authentication. Based on this I think I need OpenID Connect in order to also provide user tokens because my API needs to restrict data based on the user context.
In this approach, it is my understanding that I need to have an Authentication Server - so a few questions:
Is there software I can install to act as an OpenID Connect/oAuth2 authentication server?
Are there specific Amazon Web Services that will act as an OpenID Connect/oAuth2 Authentication Server?
I am assuming the flow will be: App makes a request to the auth server with client id + secret and receives an access token. Access token can be used to make API calls. Where are these tokens stored (I am assuming a database specific to the service/software I am using?)
When making API calls would I pass a bearer token AND a user token?
Any insight is greatly appreciated.
your understanding is not very far from reality.
Imagine you have two servers one for Authentication, this one is responsible for generating the tokens based on a Authorization Basic and base64 encoded CLientID / ClientSecret combo. This is application authentication basically. If you want to add user data as well, simply pass username / password in the post body, authenticate on the server side and then add some more data to the tokens, like the usernames, claims, roles, etc
You can control what you put in these tokens, if you use something like JWT ( Json Web Tokens ) then they are simply json bits of data.
then you have a Resource server, you hit it with a Authorization Bearer and the token you obtained from the Authorization one.
Initially the tokens are not stored anywhere, they are issued for a period of time you control. You can however do something else and store them in a db if you really want to. The expiration is much safer though, even if someone gets their hands on them they won't be available for long! In my case I used 30 minutes for token validity.
Now, you haven't specified what languages/frameworks you are looking into. If you use something like dot net then look into IdentityServer, version 4 is for Dot net core, 3 for anything below.
I also have a pretty long article on this subject if you are interested:
https://eidand.com/2015/03/28/authorization-system-with-owin-web-api-json-web-tokens/
Hopefully all this clarifies some of the questions you have.
-- Added to answer a question in comments.
The tokens contain all the information they need to be authenticated by the resource server correctly, you don't need to store them in a database for that. As I already said, you can store them but in my mind this makes them less secure. Don't forget you control what goes into a token so you can add usernames if that's what you need.
Imagine this scenario, you want to authenticate the application and the user in the same call to the Authorization Server. Do the OAuth2 in the standard way, which means authenticate the application first based on the client id / client secret. If that passes then next do the user authentication. Add the username or userid to the token you generate and any other bits of information you need. What this means that the resource server can safely assume that the username passed to it in the token has already been validated by the authentication server otherwise no token would have been generated in the the first place.
I prefer to keep these two separate myself, meaning let the AS ( Authorization Server) to deal with the application level security. Then on the RS (Resource Server) side you have an endpoint point like ValidateUser for example, which takes care of the user validation, after which you can do whatever you need. Pick whichever feels more appropriate for your project I'd say.
One final point, ALWAYS make sure all your api calls ( both AS and RS are just apis really ) are made over HTTPS and never ever have any important information transmitted via a GET call which means the URL can be intercepted. Both Headers and POST body are encrypted and secure over HTTPS.
This should address both your questions, I believe.
I need to add a token inside a token for an "act-as" schema on a custom grant type in IdentityServer3.
I tried with PreserveAccessToken but it just adds the token as a claim in the current ClaimsPrincipal, but can't find a way to nesting it as a claim when getting another token to pass along to the next service/api in the chain.
The idea behind this is for being able to keep an audit of all the hops from the end-user to the last service/api in a chain of calls.
This can be achieved using a custom grant. This allows extending the token endpoint with custom "operations" - e.g. issuing a token that contains delegated claims - e.g. a token.
docs are here: https://identityserver.github.io/Documentation/docsv2/advanced/customGrantTypes.html
here is also a sample that comes close to your scenario: https://github.com/IdentityServer/IdentityServer3.Samples/tree/master/source/Multi%20Hop%20Delegation%20(ActAsCustomGrant)
that said - this is probably the most expensive way to convey a user id over multiple hops.
If there is a trusted subsystem between the back-end system, simply transmitting the required data as payload is much simpler and much faster.
I feel silly even asking this question, but am at the limits of my understanding, and am hoping someone can provide some context.
I'm looking at the following (https://stormpath.com/blog/token-auth-for-java/) which states:
The access_token is what will be used by the browser in subsequent requests... The Authorization header is a standard header. No custom headers are required to use OAuth2. Rather than the type being Basic, in this case the type is Bearer. The access token is included directly after the Bearer keyword.
I'm in the process of building a website, for which I'll be coding both the back-end REST service, as well as the front-end browser client. Given this context, why do I need to follow any of the guidelines given above? Instead of using the access_token, Authorization and Bearer keywords, what's stopping me from using any keywords I like, or skipping the Bearer keyword entirely in the header? After all, as long as the front-end and back-end services both read/write the data in a consistent manner, shouldn't everything work fine?
Are the keywords and guidelines given above merely best-practice suggestions, to help others better understand your code/service? Are they analogous to coding-styles? Or is there any functional impact in not following the above guidelines?
Given this context, why do I need to follow any of the guidelines given above?
Because they are standardized specifications that everyone is meant to conform to if they want to interact with each other.
Instead of using the access_token, Authorization and Bearer keywords, what's stopping me from using any keywords I like, or skipping the Bearer keyword entirely in the header?
Nothing, except that it won't be OAuth anymore. It will be something custom that you created for yourself that noone else will understand how to use, unless you publish your own spec for it.
After all, as long as the front-end and back-end services both read/write the data in a consistent manner, shouldn't everything work fine?
Who is to say that you alone will ever write the only front-end? Or that the back-end will never move to another platform? Don't limit yourself to making something custom when there are open standards for this kind of stuff.
Are the keywords and guidelines given above merely best-practice suggestions, to help others better understand your code/service?
No. They are required protocol elements that help the client and server talk to each other in a standardized manner.
Authorization is a standard HTTP header used for authentication. It has a type so the client can specify what kind of authentication scheme it is using (Basic vs NTLM vs Bearer, etc). It is important for the client to specify the correct scheme being used, and for the server to handle only the schemes it recognizes.
Bearer is the type of authentication that OAuth uses in the Authorization header. access_token is a parameter of OAuth's Bearer authentication.
If you use the Authorization header (which you should), you must specify a type, as required by RFCs 2616 and 2617:
Authorization = "Authorization" ":" credentials
credentials = auth-scheme #auth-param
auth-scheme = token
auth-param = token "=" ( token | quoted-string )
So, in this case, Bearer is the auth-scheme and access_token is an auth-param.
Are they analogous to coding-styles?
No.
Or is there any functional impact in not following the above guidelines?
Yes. A client using your custom authentication system will not be able to authenticate on any server that follows the established specifications. Your server will not be able to authenticate any client that does not use your custom authentication system.
I am currently in the process of building an OAuth2 provider using the bshaffer PHP library here.
I've found IETF draft specifications that outline the implementations that specifically call out the usage of JSON Web Tokens as an authorization grant and client authentication.
The implementation that interests me however is returning a JWT in place of the regular access token, as seen here. In case of dead link, the access token response is pasted below.
{
"access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpZCI6IjYzMjIwNzg0YzUzODA3ZjVmZTc2Yjg4ZjZkNjdlMmExZTIxODlhZTEiLCJjbGllbnRfaWQiOiJUZXN0IENsaWVudCBJRCIsInVzZXJfaWQiOm51bGwsImV4cGlyZXMiOjEzODAwNDQ1NDIsInRva2VuX3R5cGUiOiJiZWFyZXIiLCJzY29wZSI6bnVsbH0.PcC4k8Q_etpU-J4yGFEuBUdeyMJhtpZFkVQ__sXpe78eSi7xTniqOOtgfWa62Y4sj5Npta8xPuDglH8Fueh_APZX4wGCiRE1P4nT4APQCOTbgcuCNXwjmP8znk9F76ID2WxThaMbmpsTTEkuyyUYQKCCdxlIcSbVvcLZUGKZ6-g",
"client_id":"CLIENT_ID",
"user_id":null,
"expires":1382630473,
"scope":null
}
It returns a JWT in place of the regularly generated access token for the normal authorization grants. Client and User credentials grants are the more important for me as we are only dealing in 1st party API access.
This implementation seems to be ideal, because I do not need to maintain a store of generated tokens, limiting the amount of infrastructure that is required. At some point if we open the API to third-parties we would need a key-store for the various pub/priv keys to validate each client's tokens, and to limit the risk if some nefarious party stole the encryption key.
I feel this is a good implementation relying on asymmetric encryption and SSL/TLS. However are there potential security risks I've missed?
The signature on the JWT will only protect any claims inside the token from tampering, but cannot protect claims external to the token. Therefore, the expires field in your structure is not protected and can be tampered with.
To protect from tampering, you want to use the exp claim.
Two valid solutions are:
double check expires against exp
drop expires and just use exp
You might prefer one over the other depending on your requirements. Personally, I'd keep it simple and go with (2)