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}