001package com.nimbusds.openid.connect.provider.spi.secrets;
002
003
004import net.jcip.annotations.ThreadSafe;
005
006import com.nimbusds.oauth2.sdk.auth.Secret;
007
008
009/**
010 * Service Provider Interface (SPI) for encoding OAuth client secrets before
011 * persisting them to storage. Can be used to symmetrically encrypt or to hash
012 * secrets (e.g. with SCrypt, BCrypt) before committing them to storage. Note,
013 * OAuth clients registered for {@code client_secret_jwt} authentication where
014 * the secret must be available in plaintext to perform HMAC must not be
015 * hashed. This also applies to secrets which may otherwise require the plain
016 * secret to be available for decoding, for example to facilitate symmetric
017 * encryption of ID tokens or UserInfo.
018 *
019 * <p>The supplied {@link SecretCodecContext context} provides access to the
020 * Connect2id server JWK set to retrieve any configured symmetric keys for the
021 * client secret encryption, as well as the client metadata to determine the
022 * registered client authentication method.
023 *
024 * <p>Implementations must be thread-safe.
025 */
026@ThreadSafe
027public interface ClientSecretStoreCodec {
028        
029        
030        /**
031         * Encodes the specified client secret before storing it. Encoding can
032         * be applied for selected clients only, based on their metadata or
033         * other criteria.
034         *
035         * @param secret The client secret. To obtain its value use the
036         *               {@link Secret#getValue()} or
037         *               {@link Secret#getValueBytes()} methods. Note, the
038         *               secrets expiration, if any, need not be encoded, it is
039         *               persisted separately. Not {@code null}.
040         * @param ctx    The codec context. Not {@code null}.
041         *
042         * @return The encoded secret. The default method returns the secret
043         *         value unencoded.
044         */
045        default String encode(final Secret secret, final SecretCodecContext ctx) {
046                return secret.getValue();
047        }
048        
049        
050        /**
051         * Encodes a client secret imported via the custom
052         * {@code preferred_client_secret} client metadata field before storing
053         * it. Encoding can be applied for selected clients only, based on
054         * their metadata or other criteria.
055         *
056         * @param secret The client secret as set by the custom
057         *               {@code preferred_client_secret} metadata field. To
058         *               obtain its value use the {@link Secret#getValue()} or
059         *               {@link Secret#getValueBytes()} methods. Note, the
060         *               secrets expiration, if any, need not be encoded, it is
061         *               persisted separately. Not {@code null}.
062         * @param ctx    The codec context. Not {@code null}.
063         *
064         * @return The encoded secret. The default method returns the secret
065         *         value unencoded.
066         */
067        default String encodeImported(final Secret secret, final SecretCodecContext ctx) {
068                return secret.getValue();
069        }
070        
071        
072        /**
073         * Decodes a client secret after retrieving it from the store.
074         *
075         * <p>If the secret is decoded to plain value the returned
076         * {@link DecodedSecret} must specify it.
077         *
078         * <p>If the secret is stored in a hashed form and cannot be decoded,
079         * the returned {@link DecodedSecret} instance must specify a
080         * {@link SecretVerifier}.
081         *
082         * @param storedValue The stored client secret value. Not {@code null}.
083         * @param ctx         The codec context. Not {@code null}.
084         *
085         * @return The decoded secret. The default method returns the stored
086         *         secret value.
087         */
088        default DecodedSecret decode(final String storedValue, final SecretCodecContext ctx) {
089                return DecodedSecret.createForPlainSecret(storedValue);
090        }
091}